@verbaly/compiler 0.8.0 → 0.10.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.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/catalog.ts","../src/check.ts","../src/codegen.ts","../src/params.ts","../src/config.ts","../src/extract.ts","../src/analyze.ts","../src/key.ts","../src/registry.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from 'node:util';\nimport { loadCatalogs, writeCatalog } from './catalog';\nimport { check, formatCheckResult } from './check';\nimport { writeDts } from './codegen';\nimport { loadConfig } from './config';\nimport { extractProject, pruneCatalogs, syncCatalogs } from './extract';\n\nconst HELP = `verbaly — i18n compiler\n\nUsage:\n verbaly extract scan sources, update catalogs and types\n verbaly check verify translations are complete (CI)\n\nOptions:\n --root <path> project root (default: cwd)\n --dir <path> catalogs directory (default: locales)\n --source <locale> source locale (default: en)\n --locales <csv> extra locales (default: from catalog files)\n --prune drop keys no longer referenced (extract)\n\nConfig file: verbaly.config.{js,mjs,json} at root (flags win).\n`;\n\nasync function main(): Promise<void> {\n const { positionals, values } = parseArgs({\n allowPositionals: true,\n options: {\n root: { type: 'string' },\n dir: { type: 'string' },\n source: { type: 'string' },\n locales: { type: 'string' },\n prune: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n\n const command = positionals[0];\n if (values.help || !command) {\n console.log(HELP);\n process.exitCode = command ? 0 : 1;\n return;\n }\n\n const cfg = await loadConfig(values.root ?? process.cwd(), {\n dir: values.dir,\n sourceLocale: values.source,\n locales: values.locales?.split(','),\n });\n\n if (command === 'extract') {\n const registry = await extractProject(cfg);\n const catalogs = loadCatalogs(cfg);\n if (values.prune) {\n const removed = pruneCatalogs(cfg, catalogs, registry);\n for (const [locale, keys] of Object.entries(removed)) {\n console.log(` ${locale}: -${keys.length} pruned`);\n }\n }\n const { added } = syncCatalogs(cfg, catalogs, registry);\n for (const locale of cfg.locales) {\n writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n const total = registry.messages().size;\n console.log(`[verbaly] ${total} messages · locales: ${cfg.locales.join(', ')}`);\n for (const [locale, keys] of Object.entries(added)) {\n console.log(` ${locale}: +${keys.length}`);\n }\n return;\n }\n\n if (command === 'check') {\n const registry = await extractProject(cfg);\n const result = check(cfg, loadCatalogs(cfg), registry);\n if (result.ok) {\n console.log('[verbaly] all translations complete ✓');\n return;\n }\n console.error(`[verbaly] check failed\\n${formatCheckResult(result)}`);\n process.exitCode = 1;\n return;\n }\n\n console.error(`[verbaly] unknown command \"${command}\"\\n${HELP}`);\n process.exitCode = 1;\n}\n\nmain().catch((error: unknown) => {\n console.error('[verbaly]', error instanceof Error ? error.message : error);\n process.exitCode = 1;\n});\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { ResolvedConfig } from './config';\n\nexport type Catalog = Record<string, string>;\nexport type Catalogs = Record<string, Catalog>;\n\nexport function catalogPath(cfg: ResolvedConfig, locale: string): string {\n return join(cfg.dir, `${locale}.json`);\n}\n\nexport function readCatalog(cfg: ResolvedConfig, locale: string): Catalog {\n try {\n return JSON.parse(readFileSync(catalogPath(cfg, locale), 'utf8')) as Catalog;\n } catch {\n return {};\n }\n}\n\nexport function loadCatalogs(cfg: ResolvedConfig): Catalogs {\n const catalogs: Catalogs = {};\n for (const locale of cfg.locales) catalogs[locale] = readCatalog(cfg, locale);\n return catalogs;\n}\n\nexport function serializeCatalog(catalog: Catalog): string {\n const sorted: Catalog = {};\n for (const key of Object.keys(catalog).sort()) {\n const value = catalog[key];\n if (value !== undefined) sorted[key] = value;\n }\n return JSON.stringify(sorted, null, 2) + '\\n';\n}\n\nexport function writeCatalog(cfg: ResolvedConfig, locale: string, catalog: Catalog): string {\n const serialized = serializeCatalog(catalog);\n mkdirSync(cfg.dir, { recursive: true });\n writeFileSync(catalogPath(cfg, locale), serialized);\n return serialized;\n}\n","import type { Catalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport type { MessageRegistry } from './registry';\n\nexport interface MissingEntry {\n locale: string;\n key: string;\n source?: string;\n}\n\nexport interface UnknownEntry {\n key: string;\n files: string[];\n}\n\nexport interface CheckResult {\n ok: boolean;\n missing: MissingEntry[];\n unknown: UnknownEntry[];\n}\n\nexport function check(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n registry: MessageRegistry,\n): CheckResult {\n const source = catalogs[cfg.sourceLocale] ?? {};\n const extracted = registry.messages();\n\n const unknown: UnknownEntry[] = [];\n for (const [key, files] of registry.usedKeys()) {\n const known =\n extracted.has(key) || cfg.locales.some((locale) => catalogs[locale]?.[key] !== undefined);\n if (!known) unknown.push({ key, files });\n }\n\n const needed = new Set<string>([...extracted.keys(), ...Object.keys(source)]);\n\n const missing: MissingEntry[] = [];\n for (const key of extracted.keys()) {\n if (!source[key]) {\n missing.push({ locale: cfg.sourceLocale, key, source: extracted.get(key)?.message });\n }\n }\n for (const locale of cfg.locales) {\n if (locale === cfg.sourceLocale) continue;\n for (const key of needed) {\n if (!catalogs[locale]?.[key]) {\n missing.push({ locale, key, source: source[key] ?? extracted.get(key)?.message });\n }\n }\n }\n\n return { ok: missing.length === 0 && unknown.length === 0, missing, unknown };\n}\n\nexport function formatCheckResult(result: CheckResult): string {\n const lines: string[] = [];\n if (result.missing.length > 0) {\n lines.push('missing translations:');\n for (const entry of result.missing) {\n const hint = entry.source ? ` — \"${truncate(entry.source, 40)}\"` : '';\n lines.push(` [${entry.locale}] ${entry.key}${hint}`);\n }\n }\n if (result.unknown.length > 0) {\n lines.push('unknown keys (not in any catalog):');\n for (const entry of result.unknown) {\n lines.push(` ${entry.key} — used in ${entry.files.join(', ')}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? text.slice(0, max - 1) + '…' : text;\n}\n","import { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { Catalog } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport { collectParams, renderParamType } from './params';\n\nexport const VIRTUAL_ID = 'virtual:verbaly';\n\nexport function generateRuntimeModule(cfg: ResolvedConfig): string {\n const others = cfg.locales.filter((locale) => locale !== cfg.sourceLocale);\n const src = JSON.stringify(cfg.sourceLocale);\n const loaders = others\n .map(\n (locale) => ` ${JSON.stringify(locale)}: () => import('${VIRTUAL_ID}/locale/${locale}'),`,\n )\n .join('\\n');\n\n return `import { createVerbaly } from 'verbaly';\nimport source from '${VIRTUAL_ID}/locale/${cfg.sourceLocale}';\n\nconst v = createVerbaly({\n locale: ${src},\n fallback: ${src},\n messages: { [${src}]: source },\n loaders: {\n${loaders}\n },\n});\n\nexport const verbaly = v;\nexport const t = v.t;\n\nexport function getLocale() {\n return v.locale;\n}\n\nexport function subscribe(listener) {\n return v.subscribe(listener);\n}\n\nexport async function setLocale(locale) {\n await v.loadLocale(locale);\n v.setLocale(locale);\n}\n`;\n}\n\nexport function generateLocaleModule(catalog: Catalog): string {\n return `export default ${JSON.stringify(catalog)};\\n`;\n}\n\nexport function generateDts(entries: Map<string, string>): string {\n const lines: string[] = [];\n for (const [key, message] of [...entries.entries()].sort(([a], [b]) => a.localeCompare(b))) {\n const params = collectParams(message);\n if (params.size === 0) {\n lines.push(` ${JSON.stringify(key)}: never;`);\n } else {\n const fields = [...params.entries()]\n .map(([name, types]) => `${JSON.stringify(name)}: ${renderParamType(types)}`)\n .join('; ');\n lines.push(` ${JSON.stringify(key)}: { ${fields} };`);\n }\n }\n\n return `// generated by verbaly — do not edit\ndeclare module 'virtual:verbaly' {\n export interface VerbalyMessages {\n${lines.join('\\n')}\n }\n export type VerbalyKey = keyof VerbalyMessages & string;\n\n export const verbaly: import('verbaly').Verbaly<VerbalyKey>;\n\n export function t<K extends VerbalyKey>(\n key: K,\n ...args: [VerbalyMessages[K]] extends [never] ? [] : [VerbalyMessages[K]]\n ): string;\n export function t(strings: TemplateStringsArray, ...values: unknown[]): string;\n export namespace t {\n export function id(\n key: string,\n ): (strings: TemplateStringsArray, ...values: unknown[]) => string;\n }\n\n export function setLocale(locale: string): Promise<void>;\n export function getLocale(): string;\n export function subscribe(listener: () => void): () => void;\n}\n\ndeclare module 'virtual:verbaly/locale/*' {\n const messages: Record<string, string>;\n export default messages;\n}\n`;\n}\n\nexport function writeDts(cfg: ResolvedConfig, entries: Map<string, string>): void {\n writeFileSync(join(cfg.root, 'verbaly.d.ts'), generateDts(entries));\n}\n","import { parse, type MessageNode } from 'verbaly';\n\nexport type ParamType = 'number' | 'string' | 'date' | 'unknown';\n\nconst PLURAL_KEYS = new Set(['zero', 'one', 'two', 'few', 'many']);\nconst NUMBER_FORMATS = new Set(['number', 'integer', 'percent', 'currency']);\nconst DATE_FORMATS = new Set(['date', 'time']);\n\nexport function collectParams(message: string): Map<string, Set<ParamType>> {\n const out = new Map<string, Set<ParamType>>();\n visit(parse(message), out);\n return out;\n}\n\nfunction visit(nodes: MessageNode[], out: Map<string, Set<ParamType>>): void {\n for (const node of nodes) {\n if (node.kind !== 'param') continue;\n const types = out.get(node.name) ?? new Set<ParamType>();\n out.set(node.name, types);\n\n if (node.variants) {\n for (const [key, body] of node.variants) {\n if (PLURAL_KEYS.has(key) || /^=\\d+$/.test(key)) types.add('number');\n else if (key !== 'other') types.add('string');\n visit(body, out);\n }\n if (types.size === 0) types.add('string');\n } else if (node.format && NUMBER_FORMATS.has(node.format)) {\n types.add('number');\n } else if (node.format && DATE_FORMATS.has(node.format)) {\n types.add('date');\n } else {\n types.add('unknown');\n }\n }\n}\n\nexport function renderParamType(types: Set<ParamType>): string {\n if (types.has('unknown') || types.size === 0) return 'unknown';\n const parts: string[] = [];\n if (types.has('number')) parts.push('number');\n if (types.has('string')) parts.push('string');\n if (types.has('date')) parts.push('Date | number | string');\n return parts.join(' | ');\n}\n","import { existsSync, readFileSync, readdirSync } from 'node:fs';\r\nimport { join, resolve } from 'node:path';\r\nimport { pathToFileURL } from 'node:url';\r\n\r\nexport interface VerbalyConfig {\r\n root?: string;\r\n dir?: string;\r\n sourceLocale?: string;\r\n locales?: string[];\r\n include?: string[];\r\n exclude?: string[];\r\n}\r\n\r\nexport interface ResolvedConfig {\r\n root: string;\r\n dir: string;\r\n sourceLocale: string;\r\n locales: string[];\r\n include: string[];\r\n exclude: string[];\r\n}\r\n\r\nexport function resolveConfig(config: VerbalyConfig = {}): ResolvedConfig {\r\n const root = resolve(config.root ?? process.cwd());\r\n const dir = resolve(root, config.dir ?? 'locales');\r\n const sourceLocale = config.sourceLocale ?? 'en';\r\n\r\n const locales = new Set<string>([sourceLocale, ...(config.locales ?? [])]);\r\n if (existsSync(dir)) {\r\n for (const file of readdirSync(dir)) {\r\n if (file.endsWith('.json')) locales.add(file.slice(0, -5));\r\n }\r\n }\r\n\r\n return {\r\n root,\r\n dir,\r\n sourceLocale,\r\n locales: [...locales],\r\n include: config.include ?? ['src/**/*.{js,jsx,ts,tsx,mjs,mts}'],\r\n exclude: config.exclude ?? ['**/node_modules/**', '**/dist/**'],\r\n };\r\n}\r\n\r\nexport async function loadConfigFile(root: string): Promise<VerbalyConfig> {\r\n for (const name of ['verbaly.config.js', 'verbaly.config.mjs']) {\r\n const path = join(root, name);\r\n if (existsSync(path)) {\r\n const mod = (await import(pathToFileURL(path).href)) as { default?: VerbalyConfig };\r\n return mod.default ?? {};\r\n }\r\n }\r\n for (const name of ['verbaly.config.ts', 'verbaly.config.mts']) {\r\n const path = join(root, name);\r\n if (existsSync(path)) return loadTsConfig(path);\r\n }\r\n const jsonPath = join(root, 'verbaly.config.json');\r\n if (existsSync(jsonPath)) {\r\n return JSON.parse(readFileSync(jsonPath, 'utf8')) as VerbalyConfig;\r\n }\r\n return {};\r\n}\r\n\r\nasync function loadTsConfig(path: string): Promise<VerbalyConfig> {\r\n try {\r\n const { bundleRequire } = await import('bundle-require');\r\n const { mod } = await bundleRequire<{ default?: VerbalyConfig }>({ filepath: path });\r\n return mod.default ?? {};\r\n } catch (error) {\r\n if (isModuleNotFound(error, 'esbuild')) {\r\n throw new Error(`[verbaly] ${path} needs esbuild — install it: pnpm add -D esbuild`, {\r\n cause: error,\r\n });\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\nfunction isModuleNotFound(error: unknown, name: string): boolean {\r\n return (\r\n error instanceof Error &&\r\n (error as { code?: string }).code === 'ERR_MODULE_NOT_FOUND' &&\r\n error.message.includes(name)\r\n );\r\n}\r\n\r\n// file config + inline overrides\r\nexport async function loadConfig(\r\n root: string,\r\n overrides: VerbalyConfig = {},\r\n): Promise<ResolvedConfig> {\r\n const fileConfig = await loadConfigFile(root);\r\n return resolveConfig({ ...fileConfig, ...definedOnly(overrides), root });\r\n}\r\n\r\nfunction definedOnly(config: VerbalyConfig): VerbalyConfig {\r\n return Object.fromEntries(\r\n Object.entries(config).filter(([, value]) => value !== undefined),\r\n ) as VerbalyConfig;\r\n}\r\n","import { readFileSync } from 'node:fs';\nimport { glob } from 'tinyglobby';\nimport { analyze } from './analyze';\nimport type { Catalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport { MessageRegistry } from './registry';\n\nexport async function extractProject(cfg: ResolvedConfig): Promise<MessageRegistry> {\n const files = await glob(cfg.include, {\n cwd: cfg.root,\n ignore: cfg.exclude,\n absolute: true,\n });\n const registry = new MessageRegistry();\n for (const file of files) {\n registry.update(file, analyze(readFileSync(file, 'utf8'), file));\n }\n return registry;\n}\n\nexport interface SyncResult {\n added: Record<string, string[]>;\n}\n\n// fills source texts + '' placeholders\nexport function syncCatalogs(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n registry: MessageRegistry,\n): SyncResult {\n const added: Record<string, string[]> = {};\n const source = (catalogs[cfg.sourceLocale] ??= {});\n\n for (const [key, msg] of registry.messages()) {\n if (source[key] !== msg.message) {\n source[key] = msg.message;\n (added[cfg.sourceLocale] ??= []).push(key);\n }\n }\n\n const needed = Object.keys(source);\n for (const locale of cfg.locales) {\n if (locale === cfg.sourceLocale) continue;\n const catalog = (catalogs[locale] ??= {});\n for (const key of needed) {\n if (catalog[key] === undefined) {\n catalog[key] = '';\n (added[locale] ??= []).push(key);\n }\n }\n }\n return { added };\n}\n\n// drops keys no longer referenced\nexport function pruneCatalogs(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n registry: MessageRegistry,\n): Record<string, string[]> {\n const keep = new Set([...registry.messages().keys(), ...registry.usedKeys().keys()]);\n const removed: Record<string, string[]> = {};\n for (const locale of cfg.locales) {\n const catalog = catalogs[locale];\n if (!catalog) continue;\n for (const key of Object.keys(catalog)) {\n if (!keep.has(key)) {\n delete catalog[key];\n (removed[locale] ??= []).push(key);\n }\n }\n }\n return removed;\n}\n","import { parse } from '@babel/parser';\r\nimport { stableKey } from './key';\r\n\r\nexport interface TaggedParam {\r\n name: string;\r\n start: number;\r\n end: number;\r\n}\r\n\r\nexport interface TransComponent {\r\n name: string;\r\n source: string;\r\n}\r\n\r\nexport interface TaggedMessage {\r\n key: string;\r\n message: string;\r\n params: TaggedParam[];\r\n start: number;\r\n end: number;\r\n tagStart: number;\r\n tagEnd: number;\r\n file: string;\r\n jsx?: { name: string; components: TransComponent[] };\r\n}\r\n\r\nexport interface UsedKey {\r\n key: string;\r\n file: string;\r\n}\r\n\r\nexport interface Analysis {\r\n tagged: TaggedMessage[];\r\n usedKeys: UsedKey[];\r\n}\r\n\r\ninterface AstNode {\r\n type: string;\r\n start: number;\r\n end: number;\r\n [key: string]: unknown;\r\n}\r\n\r\nconst SKIP_KEYS = new Set(['loc', 'leadingComments', 'trailingComments', 'innerComments', 'extra']);\r\n\r\nexport function analyze(code: string, file: string): Analysis {\r\n const jsx = /\\.[jt]sx$/.test(file);\r\n const ast = parse(code, {\r\n sourceType: 'module',\r\n errorRecovery: true,\r\n plugins: jsx ? ['typescript', 'jsx'] : ['typescript'],\r\n });\r\n\r\n const tagged: TaggedMessage[] = [];\r\n const usedKeys: UsedKey[] = [];\r\n\r\n walk(ast.program as unknown as AstNode, (node) => {\r\n if (node.type === 'TaggedTemplateExpression') {\r\n const tag = node.tag as AstNode;\r\n const explicit = explicitId(tag);\r\n if (!explicit && !isTReference(tag)) return;\r\n const quasi = node.quasi as AstNode;\r\n const message = buildMessage(code, quasi);\r\n if (!message) return;\r\n tagged.push({\r\n key: explicit ? explicit.key : stableKey(message.text),\r\n message: message.text,\r\n params: message.params,\r\n start: node.start,\r\n end: node.end,\r\n tagStart: explicit ? explicit.refStart : tag.start,\r\n tagEnd: explicit ? explicit.refEnd : tag.end,\r\n file,\r\n });\r\n } else if (node.type === 'CallExpression') {\r\n const callee = node.callee as AstNode;\r\n if (!isTReference(callee)) return;\r\n const args = node.arguments as AstNode[];\r\n const first = args[0];\r\n if (first?.type === 'StringLiteral') {\r\n usedKeys.push({ key: first.value as string, file });\r\n }\r\n } else if (node.type === 'JSXElement') {\r\n handleTrans(code, node, file, tagged, usedKeys);\r\n }\r\n });\r\n\r\n return { tagged, usedKeys };\r\n}\r\n\r\nfunction handleTrans(\r\n code: string,\r\n node: AstNode,\r\n file: string,\r\n tagged: TaggedMessage[],\r\n usedKeys: UsedKey[],\r\n): void {\r\n const opening = node.openingElement as AstNode;\r\n const nameNode = opening.name as AstNode;\r\n if (nameNode.type !== 'JSXIdentifier' || nameNode.name !== 'Trans') return;\r\n\r\n const attrs = opening.attributes as AstNode[];\r\n const idAttr = attrs.find((a) => a.type === 'JSXAttribute' && (a.name as AstNode).name === 'id');\r\n const children = node.children as AstNode[] | undefined;\r\n\r\n if (idAttr) {\r\n const value = idAttr.value as AstNode | null;\r\n if (value?.type !== 'StringLiteral') return;\r\n const id = value.value as string;\r\n // id + children → extract under the explicit key\r\n if (attrs.length === 1 && children?.length) {\r\n const built = buildTransMessage(code, children);\r\n if (built?.text.trim()) {\r\n tagged.push({\r\n key: id,\r\n message: built.text,\r\n params: built.params,\r\n start: node.start,\r\n end: node.end,\r\n tagStart: nameNode.start,\r\n tagEnd: nameNode.end,\r\n file,\r\n jsx: { name: nameNode.name as string, components: built.components },\r\n });\r\n return;\r\n }\r\n }\r\n usedKeys.push({ key: id, file });\r\n return; // runtime-first, untouched\r\n }\r\n if (attrs.length > 0) return; // hand-written props → don't guess\r\n\r\n if (!children?.length) return;\r\n\r\n const built = buildTransMessage(code, children);\r\n if (!built || !built.text.trim()) return;\r\n\r\n tagged.push({\r\n key: stableKey(built.text),\r\n message: built.text,\r\n params: built.params,\r\n start: node.start,\r\n end: node.end,\r\n tagStart: nameNode.start,\r\n tagEnd: nameNode.end,\r\n file,\r\n jsx: { name: nameNode.name as string, components: built.components },\r\n });\r\n}\r\n\r\n// t.id('key')`…` → explicit readable key\r\nfunction explicitId(tag: AstNode): { key: string; refStart: number; refEnd: number } | undefined {\r\n if (tag.type !== 'CallExpression') return undefined;\r\n const callee = tag.callee as AstNode;\r\n if (callee.type !== 'MemberExpression' || callee.computed) return undefined;\r\n const prop = callee.property as AstNode;\r\n if (prop.type !== 'Identifier' || prop.name !== 'id') return undefined;\r\n const obj = callee.object as AstNode;\r\n if (!isTReference(obj)) return undefined;\r\n const args = tag.arguments as AstNode[];\r\n const first = args[0];\r\n if (args.length !== 1 || first?.type !== 'StringLiteral') return undefined;\r\n return { key: first.value as string, refStart: obj.start, refEnd: obj.end };\r\n}\r\n\r\ninterface BuiltTrans {\r\n text: string;\r\n params: TaggedParam[];\r\n components: TransComponent[];\r\n}\r\n\r\nfunction buildTransMessage(code: string, children: AstNode[]): BuiltTrans | undefined {\r\n const params: TaggedParam[] = [];\r\n const components: TransComponent[] = [];\r\n const takenParams = new Map<string, string>();\r\n const takenTags = new Map<string, string>();\r\n\r\n function walkChildren(nodes: AstNode[]): string | undefined {\r\n let text = '';\r\n for (const child of nodes) {\r\n if (child.type === 'JSXText') {\r\n text += escapeText(cleanJsxText(child.value as string));\r\n } else if (child.type === 'JSXExpressionContainer') {\r\n const expr = child.expression as AstNode;\r\n if (expr.type === 'JSXEmptyExpression') continue;\r\n if (expr.type === 'StringLiteral') {\r\n text += escapeText(expr.value as string);\r\n continue;\r\n }\r\n if (expr.type === 'TaggedTemplateExpression') return undefined; // overlap hazard\r\n const source = code.slice(expr.start, expr.end);\r\n const name = uniqueName(deriveName(expr, params.length), source, takenParams);\r\n params.push({ name, start: expr.start, end: expr.end });\r\n text += `{${name}}`;\r\n } else if (child.type === 'JSXElement') {\r\n const opening = child.openingElement as AstNode;\r\n const nameNode = opening.name as AstNode;\r\n if (nameNode.type !== 'JSXIdentifier' || nameNode.name === 'Trans') return undefined;\r\n const source = selfClosedSource(code, opening);\r\n const tag = uniqueName((nameNode.name as string).toLowerCase(), source, takenTags);\r\n if (!components.some((c) => c.name === tag)) components.push({ name: tag, source });\r\n if (!child.closingElement) {\r\n text += `<${tag}/>`;\r\n } else {\r\n const inner = walkChildren(child.children as AstNode[]);\r\n if (inner === undefined) return undefined;\r\n text += `<${tag}>${inner}</${tag}>`;\r\n }\r\n } else {\r\n return undefined; // fragments / spread children → bail\r\n }\r\n }\r\n return text;\r\n }\r\n\r\n const text = walkChildren(children);\r\n if (text === undefined) return undefined;\r\n return { text, params, components };\r\n}\r\n\r\n// JSX text semantics: newline-indent boundaries removed, interior joins = one space\r\nfunction cleanJsxText(raw: string): string {\r\n const lines = raw.split(/\\r\\n|[\\r\\n]/);\r\n let out = '';\r\n for (let i = 0; i < lines.length; i++) {\r\n let line = lines[i]!.replace(/\\t/g, ' ');\r\n if (i !== 0) line = line.replace(/^ +/, '');\r\n if (i !== lines.length - 1) line = line.replace(/ +$/, '');\r\n if (!line) continue;\r\n if (out && i !== 0) out += ' ';\r\n out += line;\r\n }\r\n return out;\r\n}\r\n\r\nfunction selfClosedSource(code: string, opening: AstNode): string {\r\n const src = code.slice(opening.start, opening.end);\r\n return src.endsWith('/>') ? src : `${src.slice(0, -1).trimEnd()} />`;\r\n}\r\n\r\nfunction isTReference(node: AstNode): boolean {\r\n if (node.type === 'Identifier') return node.name === 't';\r\n if (node.type === 'MemberExpression' && !node.computed) {\r\n const prop = node.property as AstNode;\r\n return prop.type === 'Identifier' && prop.name === 't';\r\n }\r\n return false;\r\n}\r\n\r\ninterface BuiltMessage {\r\n text: string;\r\n params: TaggedParam[];\r\n}\r\n\r\nfunction buildMessage(code: string, quasi: AstNode): BuiltMessage | undefined {\r\n const quasis = quasi.quasis as AstNode[];\r\n const expressions = quasi.expressions as AstNode[];\r\n const params: TaggedParam[] = [];\r\n const taken = new Map<string, string>();\r\n\r\n let text = escapeText(cookedValue(quasis[0]));\r\n\r\n for (let i = 0; i < expressions.length; i++) {\r\n const expr = expressions[i];\r\n if (!expr) return undefined;\r\n const source = code.slice(expr.start, expr.end);\r\n const name = uniqueName(deriveName(expr, i), source, taken);\r\n params.push({ name, start: expr.start, end: expr.end });\r\n text += `{${name}}` + escapeText(cookedValue(quasis[i + 1]));\r\n }\r\n return { text, params };\r\n}\r\n\r\nfunction cookedValue(element: AstNode | undefined): string {\r\n if (!element) return '';\r\n const value = element.value as { cooked?: string; raw: string };\r\n return value.cooked ?? value.raw;\r\n}\r\n\r\n// literal braces → escaped\r\nfunction escapeText(text: string): string {\r\n return text.replace(/[{}]/g, (m) => m + m);\r\n}\r\n\r\nfunction deriveName(expr: AstNode, index: number): string {\r\n if (expr.type === 'Identifier') return expr.name as string;\r\n if (expr.type === 'MemberExpression' && !expr.computed) {\r\n const prop = expr.property as AstNode;\r\n if (prop.type === 'Identifier') return prop.name as string;\r\n }\r\n return `_${index}`;\r\n}\r\n\r\nfunction uniqueName(base: string, source: string, taken: Map<string, string>): string {\r\n let name = base;\r\n let n = 2;\r\n while (taken.has(name) && taken.get(name) !== source) {\r\n name = `${base}${n}`;\r\n n += 1;\r\n }\r\n taken.set(name, source);\r\n return name;\r\n}\r\n\r\nfunction walk(node: AstNode, visit: (node: AstNode) => void): void {\r\n visit(node);\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) {\r\n for (const item of value) {\r\n if (isNode(item)) walk(item, visit);\r\n }\r\n } else if (isNode(value)) {\r\n walk(value, visit);\r\n }\r\n }\r\n}\r\n\r\nfunction isNode(value: unknown): value is AstNode {\r\n return (\r\n typeof value === 'object' &&\r\n value !== null &&\r\n typeof (value as { type?: unknown }).type === 'string'\r\n );\r\n}\r\n","import { createHash } from 'node:crypto';\n\nexport function stableKey(message: string): string {\n return createHash('sha256').update(message).digest('base64url').slice(0, 8);\n}\n","import type { Analysis, TaggedMessage } from './analyze';\n\nexport class MessageRegistry {\n private files = new Map<string, Analysis>();\n\n update(file: string, analysis: Analysis): void {\n this.files.set(file, analysis);\n }\n\n remove(file: string): void {\n this.files.delete(file);\n }\n\n messages(): Map<string, TaggedMessage> {\n const out = new Map<string, TaggedMessage>();\n for (const analysis of this.files.values()) {\n for (const msg of analysis.tagged) {\n const existing = out.get(msg.key);\n if (existing) {\n if (existing.message !== msg.message) {\n console.warn(\n `[verbaly] key collision \"${msg.key}\": ` +\n `${JSON.stringify(existing.message)} vs ${JSON.stringify(msg.message)} — second dropped.`,\n );\n }\n continue;\n }\n out.set(msg.key, msg);\n }\n }\n return out;\n }\n\n usedKeys(): Map<string, string[]> {\n const out = new Map<string, string[]>();\n for (const analysis of this.files.values()) {\n for (const used of analysis.usedKeys) {\n const files = out.get(used.key) ?? [];\n if (!files.includes(used.file)) files.push(used.file);\n out.set(used.key, files);\n }\n }\n return out;\n }\n}\n"],"mappings":"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","names":["writeFileSync","join","writeFileSync","join","readFileSync","join","readFileSync","parse","parse","built","text","visit","readFileSync"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/catalog.ts","../src/check.ts","../src/codegen.ts","../src/params.ts","../src/config.ts","../src/extract.ts","../src/analyze.ts","../src/key.ts","../src/registry.ts","../src/pseudo.ts","../src/render.ts","../src/translate.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport { parseArgs } from 'node:util';\r\nimport { loadCatalogs, writeCatalog } from './catalog';\r\nimport { check, formatCheckResult } from './check';\r\nimport { writeDts } from './codegen';\r\nimport { loadConfig } from './config';\r\nimport { extractProject, pruneCatalogs, syncCatalogs } from './extract';\r\nimport { PSEUDO_LOCALE, pseudoCatalogs } from './pseudo';\r\nimport { renderSite } from './render';\r\nimport { translateCatalogs, type TranslateProvider } from './translate';\r\nimport type { ResolvedConfig } from './config';\r\n\r\nconst HELP = `verbaly — i18n compiler\r\n\r\nUsage:\r\n verbaly extract scan sources, update catalogs and types\r\n verbaly check verify translations are complete (CI)\r\n verbaly translate fill missing translations via a provider (default: claude)\r\n verbaly pseudo generate a pseudo-locale catalog for i18n QA (default: en-XA)\r\n verbaly render pre-fill data-verbaly HTML per locale (SSG, kills the FOUC)\r\n\r\nOptions:\r\n --root <path> project root (default: cwd)\r\n --dir <path> catalogs directory (default: locales)\r\n --source <locale> source locale (default: en)\r\n --locales <csv> extra locales; for translate: target locales to fill\r\n --prune drop keys no longer referenced (extract)\r\n --model <id> model override for the claude provider (translate)\r\n --dry-run list what would be translated, write nothing (translate)\r\n --locale <id> pseudo-locale id (pseudo, default: en-XA)\r\n --site <path> built site directory (render, default: dist)\r\n\r\nConfig file: verbaly.config.{js,mjs,ts,mts,json} at root (flags win).\r\nThe claude provider needs @anthropic-ai/sdk installed and ANTHROPIC_API_KEY set.\r\n`;\r\n\r\nasync function main(): Promise<void> {\r\n const { positionals, values } = parseArgs({\r\n allowPositionals: true,\r\n options: {\r\n root: { type: 'string' },\r\n dir: { type: 'string' },\r\n source: { type: 'string' },\r\n locales: { type: 'string' },\r\n prune: { type: 'boolean' },\r\n model: { type: 'string' },\r\n locale: { type: 'string' },\r\n site: { type: 'string' },\r\n 'dry-run': { type: 'boolean' },\r\n help: { type: 'boolean', short: 'h' },\r\n },\r\n });\r\n\r\n const command = positionals[0];\r\n if (values.help || !command) {\r\n console.log(HELP);\r\n process.exitCode = command ? 0 : 1;\r\n return;\r\n }\r\n\r\n const cfg = await loadConfig(values.root ?? process.cwd(), {\r\n dir: values.dir,\r\n sourceLocale: values.source,\r\n locales: values.locales?.split(','),\r\n });\r\n\r\n if (command === 'extract') {\r\n const registry = await extractProject(cfg);\r\n const catalogs = loadCatalogs(cfg);\r\n if (values.prune) {\r\n const removed = pruneCatalogs(cfg, catalogs, registry);\r\n for (const [locale, keys] of Object.entries(removed)) {\r\n console.log(` ${locale}: -${keys.length} pruned`);\r\n }\r\n }\r\n const { added } = syncCatalogs(cfg, catalogs, registry);\r\n for (const locale of cfg.locales) {\r\n writeCatalog(cfg, locale, catalogs[locale] ?? {});\r\n }\r\n writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\r\n const total = registry.messages().size;\r\n console.log(`[verbaly] ${total} messages · locales: ${cfg.locales.join(', ')}`);\r\n for (const [locale, keys] of Object.entries(added)) {\r\n console.log(` ${locale}: +${keys.length}`);\r\n }\r\n return;\r\n }\r\n\r\n if (command === 'check') {\r\n const registry = await extractProject(cfg);\r\n const result = check(cfg, loadCatalogs(cfg), registry);\r\n if (result.ok) {\r\n console.log('[verbaly] all translations complete ✓');\r\n return;\r\n }\r\n console.error(`[verbaly] check failed\\n${formatCheckResult(result)}`);\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n if (command === 'translate') {\r\n const catalogs = loadCatalogs(cfg);\r\n const provider = await resolveProvider(cfg, values.model);\r\n const result = await translateCatalogs(cfg, catalogs, provider, {\r\n locales: values.locales?.split(','),\r\n batchSize: cfg.translate.batchSize,\r\n dryRun: values['dry-run'],\r\n });\r\n\r\n if (values['dry-run']) {\r\n const entries = Object.entries(result.pending);\r\n if (entries.length === 0) {\r\n console.log('[verbaly] nothing to translate ✓');\r\n return;\r\n }\r\n for (const [locale, keys] of entries) {\r\n console.log(` ${locale}: ${keys.length} missing — ${keys.join(', ')}`);\r\n }\r\n return;\r\n }\r\n\r\n for (const locale of Object.keys(result.translated)) {\r\n writeCatalog(cfg, locale, catalogs[locale] ?? {});\r\n console.log(` ${locale}: +${result.translated[locale]!.length} translated`);\r\n }\r\n for (const [locale, keys] of Object.entries(result.invalid)) {\r\n console.warn(\r\n ` ${locale}: ${keys.length} rejected (params/tags not preserved): ${keys.join(', ')}`,\r\n );\r\n }\r\n if (Object.keys(result.translated).length === 0 && Object.keys(result.invalid).length === 0) {\r\n console.log('[verbaly] nothing to translate ✓');\r\n }\r\n return;\r\n }\r\n\r\n if (command === 'render') {\r\n const result = await renderSite(cfg, {\r\n site: values.site,\r\n locales: values.locales?.split(','),\r\n });\r\n console.log(\r\n `[verbaly] ${result.files} pages × ${result.locales.length} locales (${result.locales.join(', ')})`,\r\n );\r\n for (const [locale, keys] of Object.entries(result.missing)) {\r\n console.warn(` ${locale}: ${keys.length} keys not pre-filled — ${keys.join(', ')}`);\r\n }\r\n return;\r\n }\r\n\r\n if (command === 'pseudo') {\r\n const catalogs = loadCatalogs(cfg);\r\n const locale = values.locale ?? PSEUDO_LOCALE;\r\n const keys = pseudoCatalogs(cfg, catalogs, locale);\r\n writeCatalog(cfg, locale, catalogs[locale] ?? {});\r\n console.log(`[verbaly] ${keys.length} messages pseudo-localized → ${locale}`);\r\n return;\r\n }\r\n\r\n console.error(`[verbaly] unknown command \"${command}\"\\n${HELP}`);\r\n process.exitCode = 1;\r\n}\r\n\r\nasync function resolveProvider(\r\n cfg: ResolvedConfig,\r\n model: string | undefined,\r\n): Promise<TranslateProvider> {\r\n const configured = cfg.translate.provider;\r\n if (typeof configured === 'function') return configured;\r\n const { claudeProvider } = await import('./providers/claude');\r\n return claudeProvider({ model: model ?? cfg.translate.model });\r\n}\r\n\r\nmain().catch((error: unknown) => {\r\n console.error('[verbaly]', error instanceof Error ? error.message : error);\r\n process.exitCode = 1;\r\n});\r\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { ResolvedConfig } from './config';\n\nexport type Catalog = Record<string, string>;\nexport type Catalogs = Record<string, Catalog>;\n\nexport function catalogPath(cfg: ResolvedConfig, locale: string): string {\n return join(cfg.dir, `${locale}.json`);\n}\n\nexport function readCatalog(cfg: ResolvedConfig, locale: string): Catalog {\n try {\n return JSON.parse(readFileSync(catalogPath(cfg, locale), 'utf8')) as Catalog;\n } catch {\n return {};\n }\n}\n\nexport function loadCatalogs(cfg: ResolvedConfig): Catalogs {\n const catalogs: Catalogs = {};\n for (const locale of cfg.locales) catalogs[locale] = readCatalog(cfg, locale);\n return catalogs;\n}\n\nexport function serializeCatalog(catalog: Catalog): string {\n const sorted: Catalog = {};\n for (const key of Object.keys(catalog).sort()) {\n const value = catalog[key];\n if (value !== undefined) sorted[key] = value;\n }\n return JSON.stringify(sorted, null, 2) + '\\n';\n}\n\nexport function writeCatalog(cfg: ResolvedConfig, locale: string, catalog: Catalog): string {\n const serialized = serializeCatalog(catalog);\n mkdirSync(cfg.dir, { recursive: true });\n writeFileSync(catalogPath(cfg, locale), serialized);\n return serialized;\n}\n","import type { Catalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport type { MessageRegistry } from './registry';\n\nexport interface MissingEntry {\n locale: string;\n key: string;\n source?: string;\n}\n\nexport interface UnknownEntry {\n key: string;\n files: string[];\n}\n\nexport interface CheckResult {\n ok: boolean;\n missing: MissingEntry[];\n unknown: UnknownEntry[];\n}\n\nexport function check(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n registry: MessageRegistry,\n): CheckResult {\n const source = catalogs[cfg.sourceLocale] ?? {};\n const extracted = registry.messages();\n\n const unknown: UnknownEntry[] = [];\n for (const [key, files] of registry.usedKeys()) {\n const known =\n extracted.has(key) || cfg.locales.some((locale) => catalogs[locale]?.[key] !== undefined);\n if (!known) unknown.push({ key, files });\n }\n\n const needed = new Set<string>([...extracted.keys(), ...Object.keys(source)]);\n\n const missing: MissingEntry[] = [];\n for (const key of extracted.keys()) {\n if (!source[key]) {\n missing.push({ locale: cfg.sourceLocale, key, source: extracted.get(key)?.message });\n }\n }\n for (const locale of cfg.locales) {\n if (locale === cfg.sourceLocale) continue;\n for (const key of needed) {\n if (!catalogs[locale]?.[key]) {\n missing.push({ locale, key, source: source[key] ?? extracted.get(key)?.message });\n }\n }\n }\n\n return { ok: missing.length === 0 && unknown.length === 0, missing, unknown };\n}\n\nexport function formatCheckResult(result: CheckResult): string {\n const lines: string[] = [];\n if (result.missing.length > 0) {\n lines.push('missing translations:');\n for (const entry of result.missing) {\n const hint = entry.source ? ` — \"${truncate(entry.source, 40)}\"` : '';\n lines.push(` [${entry.locale}] ${entry.key}${hint}`);\n }\n }\n if (result.unknown.length > 0) {\n lines.push('unknown keys (not in any catalog):');\n for (const entry of result.unknown) {\n lines.push(` ${entry.key} — used in ${entry.files.join(', ')}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? text.slice(0, max - 1) + '…' : text;\n}\n","import { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { Catalog } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport { collectParams, renderParamType } from './params';\n\nexport const VIRTUAL_ID = 'virtual:verbaly';\n\nexport function generateRuntimeModule(cfg: ResolvedConfig): string {\n const others = cfg.locales.filter((locale) => locale !== cfg.sourceLocale);\n const src = JSON.stringify(cfg.sourceLocale);\n const loaders = others\n .map(\n (locale) => ` ${JSON.stringify(locale)}: () => import('${VIRTUAL_ID}/locale/${locale}'),`,\n )\n .join('\\n');\n\n return `import { createVerbaly } from 'verbaly';\nimport source from '${VIRTUAL_ID}/locale/${cfg.sourceLocale}';\n\nconst v = createVerbaly({\n locale: ${src},\n fallback: ${src},\n messages: { [${src}]: source },\n loaders: {\n${loaders}\n },\n});\n\nexport const verbaly = v;\nexport const t = v.t;\n\nexport function getLocale() {\n return v.locale;\n}\n\nexport function subscribe(listener) {\n return v.subscribe(listener);\n}\n\nexport async function setLocale(locale) {\n await v.loadLocale(locale);\n v.setLocale(locale);\n}\n`;\n}\n\nexport function generateLocaleModule(catalog: Catalog): string {\n return `export default ${JSON.stringify(catalog)};\\n`;\n}\n\nexport function generateDts(entries: Map<string, string>): string {\n const lines: string[] = [];\n for (const [key, message] of [...entries.entries()].sort(([a], [b]) => a.localeCompare(b))) {\n const params = collectParams(message);\n if (params.size === 0) {\n lines.push(` ${JSON.stringify(key)}: never;`);\n } else {\n const fields = [...params.entries()]\n .map(([name, types]) => `${JSON.stringify(name)}: ${renderParamType(types)}`)\n .join('; ');\n lines.push(` ${JSON.stringify(key)}: { ${fields} };`);\n }\n }\n\n return `// generated by verbaly — do not edit\ndeclare module 'virtual:verbaly' {\n export interface VerbalyMessages {\n${lines.join('\\n')}\n }\n export type VerbalyKey = keyof VerbalyMessages & string;\n\n export const verbaly: import('verbaly').Verbaly<VerbalyKey>;\n\n export function t<K extends VerbalyKey>(\n key: K,\n ...args: [VerbalyMessages[K]] extends [never] ? [] : [VerbalyMessages[K]]\n ): string;\n export function t(strings: TemplateStringsArray, ...values: unknown[]): string;\n export namespace t {\n export function id(\n key: string,\n ): (strings: TemplateStringsArray, ...values: unknown[]) => string;\n }\n\n export function setLocale(locale: string): Promise<void>;\n export function getLocale(): string;\n export function subscribe(listener: () => void): () => void;\n}\n\ndeclare module 'virtual:verbaly/locale/*' {\n const messages: Record<string, string>;\n export default messages;\n}\n`;\n}\n\nexport function writeDts(cfg: ResolvedConfig, entries: Map<string, string>): void {\n writeFileSync(join(cfg.root, 'verbaly.d.ts'), generateDts(entries));\n}\n","import { parse, type MessageNode } from 'verbaly';\n\nexport type ParamType = 'number' | 'string' | 'date' | 'unknown';\n\nconst PLURAL_KEYS = new Set(['zero', 'one', 'two', 'few', 'many']);\nconst NUMBER_FORMATS = new Set(['number', 'integer', 'percent', 'currency']);\nconst DATE_FORMATS = new Set(['date', 'time']);\n\nexport function collectParams(message: string): Map<string, Set<ParamType>> {\n const out = new Map<string, Set<ParamType>>();\n visit(parse(message), out);\n return out;\n}\n\nfunction visit(nodes: MessageNode[], out: Map<string, Set<ParamType>>): void {\n for (const node of nodes) {\n if (node.kind !== 'param') continue;\n const types = out.get(node.name) ?? new Set<ParamType>();\n out.set(node.name, types);\n\n if (node.variants) {\n for (const [key, body] of node.variants) {\n if (PLURAL_KEYS.has(key) || /^=\\d+$/.test(key)) types.add('number');\n else if (key !== 'other') types.add('string');\n visit(body, out);\n }\n if (types.size === 0) types.add('string');\n } else if (node.format && NUMBER_FORMATS.has(node.format)) {\n types.add('number');\n } else if (node.format && DATE_FORMATS.has(node.format)) {\n types.add('date');\n } else {\n types.add('unknown');\n }\n }\n}\n\nexport function renderParamType(types: Set<ParamType>): string {\n if (types.has('unknown') || types.size === 0) return 'unknown';\n const parts: string[] = [];\n if (types.has('number')) parts.push('number');\n if (types.has('string')) parts.push('string');\n if (types.has('date')) parts.push('Date | number | string');\n return parts.join(' | ');\n}\n","import { existsSync, readFileSync, readdirSync } from 'node:fs';\r\nimport { join, resolve } from 'node:path';\r\nimport { pathToFileURL } from 'node:url';\r\nimport type { TranslateProvider } from './translate';\r\n\r\nexport interface TranslateConfig {\r\n provider?: 'claude' | TranslateProvider;\r\n model?: string;\r\n batchSize?: number;\r\n}\r\n\r\nexport interface VerbalyConfig {\r\n root?: string;\r\n dir?: string;\r\n sourceLocale?: string;\r\n locales?: string[];\r\n include?: string[];\r\n exclude?: string[];\r\n translate?: TranslateConfig;\r\n}\r\n\r\nexport interface ResolvedConfig {\r\n root: string;\r\n dir: string;\r\n sourceLocale: string;\r\n locales: string[];\r\n include: string[];\r\n exclude: string[];\r\n translate: TranslateConfig;\r\n}\r\n\r\nexport function resolveConfig(config: VerbalyConfig = {}): ResolvedConfig {\r\n const root = resolve(config.root ?? process.cwd());\r\n const dir = resolve(root, config.dir ?? 'locales');\r\n const sourceLocale = config.sourceLocale ?? 'en';\r\n\r\n const locales = new Set<string>([sourceLocale, ...(config.locales ?? [])]);\r\n if (existsSync(dir)) {\r\n for (const file of readdirSync(dir)) {\r\n if (file.endsWith('.json')) locales.add(file.slice(0, -5));\r\n }\r\n }\r\n\r\n return {\r\n root,\r\n dir,\r\n sourceLocale,\r\n locales: [...locales],\r\n include: config.include ?? ['src/**/*.{js,jsx,ts,tsx,mjs,mts}'],\r\n exclude: config.exclude ?? ['**/node_modules/**', '**/dist/**'],\r\n translate: config.translate ?? {},\r\n };\r\n}\r\n\r\nexport async function loadConfigFile(root: string): Promise<VerbalyConfig> {\r\n for (const name of ['verbaly.config.js', 'verbaly.config.mjs']) {\r\n const path = join(root, name);\r\n if (existsSync(path)) {\r\n const mod = (await import(pathToFileURL(path).href)) as { default?: VerbalyConfig };\r\n return mod.default ?? {};\r\n }\r\n }\r\n for (const name of ['verbaly.config.ts', 'verbaly.config.mts']) {\r\n const path = join(root, name);\r\n if (existsSync(path)) return loadTsConfig(path);\r\n }\r\n const jsonPath = join(root, 'verbaly.config.json');\r\n if (existsSync(jsonPath)) {\r\n return JSON.parse(readFileSync(jsonPath, 'utf8')) as VerbalyConfig;\r\n }\r\n return {};\r\n}\r\n\r\nasync function loadTsConfig(path: string): Promise<VerbalyConfig> {\r\n try {\r\n const { bundleRequire } = await import('bundle-require');\r\n const { mod } = await bundleRequire<{ default?: VerbalyConfig }>({ filepath: path });\r\n return mod.default ?? {};\r\n } catch (error) {\r\n if (isModuleNotFound(error, 'esbuild')) {\r\n throw new Error(`[verbaly] ${path} needs esbuild — install it: pnpm add -D esbuild`, {\r\n cause: error,\r\n });\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\nfunction isModuleNotFound(error: unknown, name: string): boolean {\r\n return (\r\n error instanceof Error &&\r\n (error as { code?: string }).code === 'ERR_MODULE_NOT_FOUND' &&\r\n error.message.includes(name)\r\n );\r\n}\r\n\r\n// file config + inline overrides\r\nexport async function loadConfig(\r\n root: string,\r\n overrides: VerbalyConfig = {},\r\n): Promise<ResolvedConfig> {\r\n const fileConfig = await loadConfigFile(root);\r\n return resolveConfig({ ...fileConfig, ...definedOnly(overrides), root });\r\n}\r\n\r\nfunction definedOnly(config: VerbalyConfig): VerbalyConfig {\r\n return Object.fromEntries(\r\n Object.entries(config).filter(([, value]) => value !== undefined),\r\n ) as VerbalyConfig;\r\n}\r\n","import { readFileSync } from 'node:fs';\nimport { glob } from 'tinyglobby';\nimport { analyze } from './analyze';\nimport type { Catalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport { MessageRegistry } from './registry';\n\nexport async function extractProject(cfg: ResolvedConfig): Promise<MessageRegistry> {\n const files = await glob(cfg.include, {\n cwd: cfg.root,\n ignore: cfg.exclude,\n absolute: true,\n });\n const registry = new MessageRegistry();\n for (const file of files) {\n registry.update(file, analyze(readFileSync(file, 'utf8'), file));\n }\n return registry;\n}\n\nexport interface SyncResult {\n added: Record<string, string[]>;\n}\n\n// fills source texts + '' placeholders\nexport function syncCatalogs(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n registry: MessageRegistry,\n): SyncResult {\n const added: Record<string, string[]> = {};\n const source = (catalogs[cfg.sourceLocale] ??= {});\n\n for (const [key, msg] of registry.messages()) {\n if (source[key] !== msg.message) {\n source[key] = msg.message;\n (added[cfg.sourceLocale] ??= []).push(key);\n }\n }\n\n const needed = Object.keys(source);\n for (const locale of cfg.locales) {\n if (locale === cfg.sourceLocale) continue;\n const catalog = (catalogs[locale] ??= {});\n for (const key of needed) {\n if (catalog[key] === undefined) {\n catalog[key] = '';\n (added[locale] ??= []).push(key);\n }\n }\n }\n return { added };\n}\n\n// drops keys no longer referenced\nexport function pruneCatalogs(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n registry: MessageRegistry,\n): Record<string, string[]> {\n const keep = new Set([...registry.messages().keys(), ...registry.usedKeys().keys()]);\n const removed: Record<string, string[]> = {};\n for (const locale of cfg.locales) {\n const catalog = catalogs[locale];\n if (!catalog) continue;\n for (const key of Object.keys(catalog)) {\n if (!keep.has(key)) {\n delete catalog[key];\n (removed[locale] ??= []).push(key);\n }\n }\n }\n return removed;\n}\n","import { parse } from '@babel/parser';\r\nimport { stableKey } from './key';\r\n\r\nexport interface TaggedParam {\r\n name: string;\r\n start: number;\r\n end: number;\r\n}\r\n\r\nexport interface TransComponent {\r\n name: string;\r\n source: string;\r\n}\r\n\r\nexport interface TaggedMessage {\r\n key: string;\r\n message: string;\r\n params: TaggedParam[];\r\n start: number;\r\n end: number;\r\n tagStart: number;\r\n tagEnd: number;\r\n file: string;\r\n jsx?: { name: string; components: TransComponent[] };\r\n}\r\n\r\nexport interface UsedKey {\r\n key: string;\r\n file: string;\r\n}\r\n\r\nexport interface Analysis {\r\n tagged: TaggedMessage[];\r\n usedKeys: UsedKey[];\r\n}\r\n\r\ninterface AstNode {\r\n type: string;\r\n start: number;\r\n end: number;\r\n [key: string]: unknown;\r\n}\r\n\r\nconst SKIP_KEYS = new Set(['loc', 'leadingComments', 'trailingComments', 'innerComments', 'extra']);\r\n\r\nexport function analyze(code: string, file: string): Analysis {\r\n const jsx = /\\.[jt]sx$/.test(file);\r\n const ast = parse(code, {\r\n sourceType: 'module',\r\n errorRecovery: true,\r\n plugins: jsx ? ['typescript', 'jsx'] : ['typescript'],\r\n });\r\n\r\n const tagged: TaggedMessage[] = [];\r\n const usedKeys: UsedKey[] = [];\r\n\r\n walk(ast.program as unknown as AstNode, (node) => {\r\n if (node.type === 'TaggedTemplateExpression') {\r\n const tag = node.tag as AstNode;\r\n const explicit = explicitId(tag);\r\n if (!explicit && !isTReference(tag)) return;\r\n const quasi = node.quasi as AstNode;\r\n const message = buildMessage(code, quasi);\r\n if (!message) return;\r\n tagged.push({\r\n key: explicit ? explicit.key : stableKey(message.text),\r\n message: message.text,\r\n params: message.params,\r\n start: node.start,\r\n end: node.end,\r\n tagStart: explicit ? explicit.refStart : tag.start,\r\n tagEnd: explicit ? explicit.refEnd : tag.end,\r\n file,\r\n });\r\n } else if (node.type === 'CallExpression') {\r\n const callee = node.callee as AstNode;\r\n if (!isTReference(callee)) return;\r\n const args = node.arguments as AstNode[];\r\n const first = args[0];\r\n if (first?.type === 'StringLiteral') {\r\n usedKeys.push({ key: first.value as string, file });\r\n }\r\n } else if (node.type === 'JSXElement') {\r\n handleTrans(code, node, file, tagged, usedKeys);\r\n }\r\n });\r\n\r\n return { tagged, usedKeys };\r\n}\r\n\r\nfunction handleTrans(\r\n code: string,\r\n node: AstNode,\r\n file: string,\r\n tagged: TaggedMessage[],\r\n usedKeys: UsedKey[],\r\n): void {\r\n const opening = node.openingElement as AstNode;\r\n const nameNode = opening.name as AstNode;\r\n if (nameNode.type !== 'JSXIdentifier' || nameNode.name !== 'Trans') return;\r\n\r\n const attrs = opening.attributes as AstNode[];\r\n const idAttr = attrs.find((a) => a.type === 'JSXAttribute' && (a.name as AstNode).name === 'id');\r\n const children = node.children as AstNode[] | undefined;\r\n\r\n if (idAttr) {\r\n const value = idAttr.value as AstNode | null;\r\n if (value?.type !== 'StringLiteral') return;\r\n const id = value.value as string;\r\n // id + children → extract under the explicit key\r\n if (attrs.length === 1 && children?.length) {\r\n const built = buildTransMessage(code, children);\r\n if (built?.text.trim()) {\r\n tagged.push({\r\n key: id,\r\n message: built.text,\r\n params: built.params,\r\n start: node.start,\r\n end: node.end,\r\n tagStart: nameNode.start,\r\n tagEnd: nameNode.end,\r\n file,\r\n jsx: { name: nameNode.name as string, components: built.components },\r\n });\r\n return;\r\n }\r\n }\r\n usedKeys.push({ key: id, file });\r\n return; // runtime-first, untouched\r\n }\r\n if (attrs.length > 0) return; // hand-written props → don't guess\r\n\r\n if (!children?.length) return;\r\n\r\n const built = buildTransMessage(code, children);\r\n if (!built || !built.text.trim()) return;\r\n\r\n tagged.push({\r\n key: stableKey(built.text),\r\n message: built.text,\r\n params: built.params,\r\n start: node.start,\r\n end: node.end,\r\n tagStart: nameNode.start,\r\n tagEnd: nameNode.end,\r\n file,\r\n jsx: { name: nameNode.name as string, components: built.components },\r\n });\r\n}\r\n\r\n// t.id('key')`…` → explicit readable key\r\nfunction explicitId(tag: AstNode): { key: string; refStart: number; refEnd: number } | undefined {\r\n if (tag.type !== 'CallExpression') return undefined;\r\n const callee = tag.callee as AstNode;\r\n if (callee.type !== 'MemberExpression' || callee.computed) return undefined;\r\n const prop = callee.property as AstNode;\r\n if (prop.type !== 'Identifier' || prop.name !== 'id') return undefined;\r\n const obj = callee.object as AstNode;\r\n if (!isTReference(obj)) return undefined;\r\n const args = tag.arguments as AstNode[];\r\n const first = args[0];\r\n if (args.length !== 1 || first?.type !== 'StringLiteral') return undefined;\r\n return { key: first.value as string, refStart: obj.start, refEnd: obj.end };\r\n}\r\n\r\ninterface BuiltTrans {\r\n text: string;\r\n params: TaggedParam[];\r\n components: TransComponent[];\r\n}\r\n\r\nfunction buildTransMessage(code: string, children: AstNode[]): BuiltTrans | undefined {\r\n const params: TaggedParam[] = [];\r\n const components: TransComponent[] = [];\r\n const takenParams = new Map<string, string>();\r\n const takenTags = new Map<string, string>();\r\n\r\n function walkChildren(nodes: AstNode[]): string | undefined {\r\n let text = '';\r\n for (const child of nodes) {\r\n if (child.type === 'JSXText') {\r\n text += escapeText(cleanJsxText(child.value as string));\r\n } else if (child.type === 'JSXExpressionContainer') {\r\n const expr = child.expression as AstNode;\r\n if (expr.type === 'JSXEmptyExpression') continue;\r\n if (expr.type === 'StringLiteral') {\r\n text += escapeText(expr.value as string);\r\n continue;\r\n }\r\n if (expr.type === 'TaggedTemplateExpression') return undefined; // overlap hazard\r\n const source = code.slice(expr.start, expr.end);\r\n const name = uniqueName(deriveName(expr, params.length), source, takenParams);\r\n params.push({ name, start: expr.start, end: expr.end });\r\n text += `{${name}}`;\r\n } else if (child.type === 'JSXElement') {\r\n const opening = child.openingElement as AstNode;\r\n const nameNode = opening.name as AstNode;\r\n if (nameNode.type !== 'JSXIdentifier' || nameNode.name === 'Trans') return undefined;\r\n const source = selfClosedSource(code, opening);\r\n const tag = uniqueName((nameNode.name as string).toLowerCase(), source, takenTags);\r\n if (!components.some((c) => c.name === tag)) components.push({ name: tag, source });\r\n if (!child.closingElement) {\r\n text += `<${tag}/>`;\r\n } else {\r\n const inner = walkChildren(child.children as AstNode[]);\r\n if (inner === undefined) return undefined;\r\n text += `<${tag}>${inner}</${tag}>`;\r\n }\r\n } else {\r\n return undefined; // fragments / spread children → bail\r\n }\r\n }\r\n return text;\r\n }\r\n\r\n const text = walkChildren(children);\r\n if (text === undefined) return undefined;\r\n return { text, params, components };\r\n}\r\n\r\n// JSX text semantics: newline-indent boundaries removed, interior joins = one space\r\nfunction cleanJsxText(raw: string): string {\r\n const lines = raw.split(/\\r\\n|[\\r\\n]/);\r\n let out = '';\r\n for (let i = 0; i < lines.length; i++) {\r\n let line = lines[i]!.replace(/\\t/g, ' ');\r\n if (i !== 0) line = line.replace(/^ +/, '');\r\n if (i !== lines.length - 1) line = line.replace(/ +$/, '');\r\n if (!line) continue;\r\n if (out && i !== 0) out += ' ';\r\n out += line;\r\n }\r\n return out;\r\n}\r\n\r\nfunction selfClosedSource(code: string, opening: AstNode): string {\r\n const src = code.slice(opening.start, opening.end);\r\n return src.endsWith('/>') ? src : `${src.slice(0, -1).trimEnd()} />`;\r\n}\r\n\r\nfunction isTReference(node: AstNode): boolean {\r\n if (node.type === 'Identifier') return node.name === 't';\r\n if (node.type === 'MemberExpression' && !node.computed) {\r\n const prop = node.property as AstNode;\r\n return prop.type === 'Identifier' && prop.name === 't';\r\n }\r\n return false;\r\n}\r\n\r\ninterface BuiltMessage {\r\n text: string;\r\n params: TaggedParam[];\r\n}\r\n\r\nfunction buildMessage(code: string, quasi: AstNode): BuiltMessage | undefined {\r\n const quasis = quasi.quasis as AstNode[];\r\n const expressions = quasi.expressions as AstNode[];\r\n const params: TaggedParam[] = [];\r\n const taken = new Map<string, string>();\r\n\r\n let text = escapeText(cookedValue(quasis[0]));\r\n\r\n for (let i = 0; i < expressions.length; i++) {\r\n const expr = expressions[i];\r\n if (!expr) return undefined;\r\n const source = code.slice(expr.start, expr.end);\r\n const name = uniqueName(deriveName(expr, i), source, taken);\r\n params.push({ name, start: expr.start, end: expr.end });\r\n text += `{${name}}` + escapeText(cookedValue(quasis[i + 1]));\r\n }\r\n return { text, params };\r\n}\r\n\r\nfunction cookedValue(element: AstNode | undefined): string {\r\n if (!element) return '';\r\n const value = element.value as { cooked?: string; raw: string };\r\n return value.cooked ?? value.raw;\r\n}\r\n\r\n// literal braces → escaped\r\nfunction escapeText(text: string): string {\r\n return text.replace(/[{}]/g, (m) => m + m);\r\n}\r\n\r\nfunction deriveName(expr: AstNode, index: number): string {\r\n if (expr.type === 'Identifier') return expr.name as string;\r\n if (expr.type === 'MemberExpression' && !expr.computed) {\r\n const prop = expr.property as AstNode;\r\n if (prop.type === 'Identifier') return prop.name as string;\r\n }\r\n return `_${index}`;\r\n}\r\n\r\nfunction uniqueName(base: string, source: string, taken: Map<string, string>): string {\r\n let name = base;\r\n let n = 2;\r\n while (taken.has(name) && taken.get(name) !== source) {\r\n name = `${base}${n}`;\r\n n += 1;\r\n }\r\n taken.set(name, source);\r\n return name;\r\n}\r\n\r\nfunction walk(node: AstNode, visit: (node: AstNode) => void): void {\r\n visit(node);\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) {\r\n for (const item of value) {\r\n if (isNode(item)) walk(item, visit);\r\n }\r\n } else if (isNode(value)) {\r\n walk(value, visit);\r\n }\r\n }\r\n}\r\n\r\nfunction isNode(value: unknown): value is AstNode {\r\n return (\r\n typeof value === 'object' &&\r\n value !== null &&\r\n typeof (value as { type?: unknown }).type === 'string'\r\n );\r\n}\r\n","import { createHash } from 'node:crypto';\n\nexport function stableKey(message: string): string {\n return createHash('sha256').update(message).digest('base64url').slice(0, 8);\n}\n","import type { Analysis, TaggedMessage } from './analyze';\n\nexport class MessageRegistry {\n private files = new Map<string, Analysis>();\n\n update(file: string, analysis: Analysis): void {\n this.files.set(file, analysis);\n }\n\n remove(file: string): void {\n this.files.delete(file);\n }\n\n messages(): Map<string, TaggedMessage> {\n const out = new Map<string, TaggedMessage>();\n for (const analysis of this.files.values()) {\n for (const msg of analysis.tagged) {\n const existing = out.get(msg.key);\n if (existing) {\n if (existing.message !== msg.message) {\n console.warn(\n `[verbaly] key collision \"${msg.key}\": ` +\n `${JSON.stringify(existing.message)} vs ${JSON.stringify(msg.message)} — second dropped.`,\n );\n }\n continue;\n }\n out.set(msg.key, msg);\n }\n }\n return out;\n }\n\n usedKeys(): Map<string, string[]> {\n const out = new Map<string, string[]>();\n for (const analysis of this.files.values()) {\n for (const used of analysis.usedKeys) {\n const files = out.get(used.key) ?? [];\n if (!files.includes(used.file)) files.push(used.file);\n out.set(used.key, files);\n }\n }\n return out;\n }\n}\n","import type { Catalog, Catalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\n\nexport const PSEUDO_LOCALE = 'en-XA';\n\nconst ACCENTS: Record<string, string> = {\n a: 'á', b: 'ƀ', c: 'ç', d: 'đ', e: 'é', f: 'ƒ', g: 'ğ', h: 'ĥ', i: 'í', j: 'ĵ',\n k: 'ķ', l: 'ĺ', m: 'ɱ', n: 'ñ', o: 'ó', p: 'þ', q: 'ǫ', r: 'ŕ', s: 'š', t: 'ţ',\n u: 'ú', v: 'ṽ', w: 'ŵ', x: 'ẋ', y: 'ý', z: 'ž',\n A: 'Á', B: 'Ɓ', C: 'Ç', D: 'Đ', E: 'É', F: 'Ƒ', G: 'Ğ', H: 'Ĥ', I: 'Í', J: 'Ĵ',\n K: 'Ķ', L: 'Ĺ', M: 'Ḿ', N: 'Ñ', O: 'Ó', P: 'Þ', Q: 'Ǫ', R: 'Ŕ', S: 'Š', T: 'Ţ',\n U: 'Ú', V: 'Ṽ', W: 'Ŵ', X: 'Ẍ', Y: 'Ý', Z: 'Ž',\n};\n\nconst TAG_AT = /<\\/?[a-zA-Z][\\w-]*\\/?>/y;\n\n// params, variant blocks, tags and escapes survive verbatim\nexport function pseudoLocalize(message: string): string {\n let out = '';\n let letters = 0;\n let i = 0;\n while (i < message.length) {\n const two = message.slice(i, i + 2);\n if (two === '{{' || two === '}}' || two === '||' || two === '##') {\n out += two;\n i += 2;\n continue;\n }\n const ch = message[i]!;\n if (ch === '{') {\n const end = matchBrace(message, i);\n out += message.slice(i, end);\n i = end;\n continue;\n }\n if (ch === '<') {\n TAG_AT.lastIndex = i;\n const m = TAG_AT.exec(message);\n if (m) {\n out += m[0];\n i += m[0].length;\n continue;\n }\n }\n const mapped = ACCENTS[ch];\n if (mapped) {\n out += mapped;\n letters += 1;\n } else {\n out += ch;\n }\n i += 1;\n }\n const pad = '~'.repeat(Math.ceil(letters / 3));\n return `⟦${out}${pad ? ' ' + pad : ''}⟧`;\n}\n\nfunction matchBrace(message: string, start: number): number {\n let depth = 0;\n for (let i = start; i < message.length; i++) {\n const two = message.slice(i, i + 2);\n if (two === '{{' || two === '}}') {\n i += 1;\n continue;\n }\n const ch = message[i];\n if (ch === '{') depth += 1;\n else if (ch === '}') {\n depth -= 1;\n if (depth === 0) return i + 1;\n }\n }\n return message.length; // unbalanced → verbatim\n}\n\n// regenerates the whole pseudo catalog from the source catalog\nexport function pseudoCatalogs(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n locale: string = PSEUDO_LOCALE,\n): string[] {\n const source = catalogs[cfg.sourceLocale] ?? {};\n const target: Catalog = {};\n for (const [key, msg] of Object.entries(source)) {\n target[key] = msg ? pseudoLocalize(msg) : '';\n }\n catalogs[locale] = target;\n return Object.keys(target).filter((key) => target[key]);\n}\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\nimport MagicString from 'magic-string';\nimport { glob } from 'tinyglobby';\nimport { createVerbaly, parseTags, RICH_TAGS, type Params, type TagNode } from 'verbaly';\nimport type { Catalogs } from './catalog';\nimport { loadCatalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\n\nexport interface RenderHtmlOptions {\n locale: string;\n catalogs: Catalogs;\n sourceLocale?: string;\n attribute?: string;\n richTags?: string[];\n setLang?: boolean;\n}\n\nexport interface RenderHtmlResult {\n html: string;\n missing: string[];\n}\n\nconst VOID_TAGS = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr',\n]);\n\nconst START_TAG = /<([a-zA-Z][a-zA-Z0-9-]*)((?:\"[^\"]*\"|'[^']*'|[^\"'>])*)>/g;\nconst ATTR = /([^\\s=/\"'<>]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/g;\n\n// pre-fills data-verbaly elements for one locale; the runtime stays functional\nexport function renderHtml(html: string, options: RenderHtmlOptions): RenderHtmlResult {\n const attr = options.attribute ?? 'data-verbaly';\n const argsAttr = `${attr}-args`;\n const attrsAttr = `${attr}-attr`;\n const richAttr = `${attr}-rich`;\n const richTags = new Set(options.richTags ?? RICH_TAGS);\n const sourceLocale = options.sourceLocale ?? 'en';\n\n // '' entries count as untranslated → fall back\n const messages: Record<string, Record<string, string>> = {};\n for (const [locale, catalog] of Object.entries(options.catalogs)) {\n const clean: Record<string, string> = {};\n for (const [key, msg] of Object.entries(catalog)) if (msg) clean[key] = msg;\n messages[locale] = clean;\n }\n const v = createVerbaly({ locale: options.locale, fallback: sourceLocale, messages });\n const t = v.t as unknown as (key: string, params?: Params) => string;\n\n const ms = new MagicString(html);\n const missing = new Set<string>();\n const skip = protectedRanges(html);\n const inSkip = (index: number): boolean =>\n skip.some(([from, to]) => index >= from && index < to);\n\n START_TAG.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = START_TAG.exec(html)) !== null) {\n if (inSkip(m.index)) continue;\n const [full, rawName, attrChunk] = m as unknown as [string, string, string];\n const tagName = rawName.toLowerCase();\n const openEnd = m.index + full.length;\n\n const chunkStart = m.index + 1 + rawName.length;\n\n if (tagName === 'html' && options.setLang !== false) {\n setAttribute(ms, html, chunkStart, openEnd, attrChunk, 'lang', options.locale);\n continue;\n }\n\n const attrs = parseAttrs(attrChunk);\n const key = attrs.get(attr);\n const attrMapRaw = attrs.get(attrsAttr);\n if (key === undefined && attrMapRaw === undefined) continue;\n\n const args = parseArgs(attrs.get(argsAttr));\n\n if (key) {\n if (!v.has(key)) {\n missing.add(key);\n } else if (!VOID_TAGS.has(tagName) && !attrChunk.trimEnd().endsWith('/')) {\n const close = findClose(html, tagName, openEnd, inSkip);\n if (close) {\n const text = t(key, args);\n const content = attrs.has(richAttr)\n ? richToHtml(parseTags(text), richTags)\n : escapeHtml(text);\n if (html.slice(openEnd, close.contentEnd) !== content) {\n if (openEnd === close.contentEnd) ms.appendLeft(openEnd, content);\n else ms.overwrite(openEnd, close.contentEnd, content);\n }\n }\n }\n }\n\n if (attrMapRaw !== undefined) {\n const map = parseArgs(attrMapRaw);\n if (map) {\n for (const [name, attrKey] of Object.entries(map)) {\n if (typeof attrKey !== 'string' || name.toLowerCase().startsWith('on')) continue;\n if (!v.has(attrKey)) {\n missing.add(attrKey);\n continue;\n }\n setAttribute(ms, html, chunkStart, openEnd, attrChunk, name, t(attrKey, args));\n }\n }\n }\n }\n\n return { html: ms.toString(), missing: [...missing] };\n}\n\nexport interface RenderSiteOptions {\n site?: string;\n locales?: string[];\n attribute?: string;\n richTags?: string[];\n}\n\nexport interface RenderSiteResult {\n files: number;\n locales: string[];\n missing: Record<string, string[]>;\n}\n\n// mirrors the built site per locale: dist/index.html → dist/<locale>/index.html\nexport async function renderSite(\n cfg: ResolvedConfig,\n options: RenderSiteOptions = {},\n): Promise<RenderSiteResult> {\n const site = join(cfg.root, options.site ?? 'dist');\n const locales = options.locales ?? cfg.locales;\n const catalogs = loadCatalogs(cfg);\n const files = await glob('**/*.html', {\n cwd: site,\n absolute: true,\n ignore: locales.map((locale) => `${locale}/**`),\n });\n\n const missing: Record<string, string[]> = {};\n for (const file of files) {\n const html = readFileSync(file, 'utf8');\n const rel = relative(site, file);\n for (const locale of locales) {\n const result = renderHtml(html, {\n locale,\n catalogs,\n sourceLocale: cfg.sourceLocale,\n attribute: options.attribute,\n richTags: options.richTags,\n });\n for (const key of result.missing) {\n const list = (missing[locale] ??= []);\n if (!list.includes(key)) list.push(key);\n }\n const out = locale === cfg.sourceLocale ? file : join(site, locale, rel);\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, result.html);\n }\n }\n return { files: files.length, locales: [...locales], missing };\n}\n\nfunction parseAttrs(chunk: string): Map<string, string> {\n const attrs = new Map<string, string>();\n ATTR.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = ATTR.exec(chunk)) !== null) {\n attrs.set(m[1]!.toLowerCase(), m[2] ?? m[3] ?? m[4] ?? '');\n }\n return attrs;\n}\n\nfunction parseArgs(raw: string | undefined): Params | undefined {\n if (!raw) return undefined;\n try {\n return JSON.parse(decodeEntities(raw)) as Params;\n } catch {\n console.warn(`[verbaly] invalid args JSON: ${raw}`);\n return undefined;\n }\n}\n\n// comments and script/style bodies are opaque to the scanner\nfunction protectedRanges(html: string): Array<[number, number]> {\n const ranges: Array<[number, number]> = [];\n const re = /<!--[\\s\\S]*?-->|<script\\b[\\s\\S]*?<\\/script\\s*>|<style\\b[\\s\\S]*?<\\/style\\s*>/gi;\n let m: RegExpExecArray | null;\n while ((m = re.exec(html)) !== null) {\n // keep script/style open tags scannable; protect only their bodies\n const openEnd = m[0].startsWith('<!--') ? m.index : html.indexOf('>', m.index) + 1;\n ranges.push([openEnd, m.index + m[0].length]);\n }\n return ranges;\n}\n\nfunction findClose(\n html: string,\n tagName: string,\n from: number,\n inSkip: (index: number) => boolean,\n): { contentEnd: number } | null {\n const re = new RegExp(\n `<${tagName}(?=[\\\\s/>])(?:\"[^\"]*\"|'[^']*'|[^\"'>])*>|</${tagName}\\\\s*>`,\n 'gi',\n );\n re.lastIndex = from;\n let depth = 1;\n let m: RegExpExecArray | null;\n while ((m = re.exec(html)) !== null) {\n if (inSkip(m.index)) continue;\n if (m[0][1] === '/') {\n depth -= 1;\n if (depth === 0) return { contentEnd: m.index };\n } else if (!m[0].endsWith('/>')) {\n depth += 1;\n }\n }\n return null;\n}\n\nfunction setAttribute(\n ms: MagicString,\n html: string,\n chunkStart: number,\n openEnd: number,\n attrChunk: string,\n name: string,\n value: string,\n): void {\n const escaped = escapeAttr(value);\n const existing = new RegExp(`(\\\\s${name}\\\\s*=\\\\s*)(\"[^\"]*\"|'[^']*'|[^\\\\s>]+)`, 'i').exec(\n attrChunk,\n );\n if (existing) {\n const valueStart = chunkStart + existing.index + existing[1]!.length;\n const valueEnd = valueStart + existing[2]!.length;\n if (html.slice(valueStart, valueEnd) !== `\"${escaped}\"`) {\n ms.overwrite(valueStart, valueEnd, `\"${escaped}\"`);\n }\n return;\n }\n const selfClosing = html.slice(openEnd - 2, openEnd) === '/>';\n const insertAt = openEnd - (selfClosing ? 2 : 1);\n ms.appendLeft(insertAt, ` ${name}=\"${escaped}\"`);\n}\n\nfunction richToHtml(nodes: TagNode[], allowed: Set<string>): string {\n let out = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n out += escapeHtml(node);\n } else if (allowed.has(node.name)) {\n out += `<${node.name}>${richToHtml(node.children, allowed)}</${node.name}>`;\n } else {\n out += richToHtml(node.children, allowed); // unknown tag → unwrap\n }\n }\n return out;\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction escapeAttr(text: string): string {\n return escapeHtml(text).replace(/\"/g, '&quot;');\n}\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&amp;/g, '&');\n}\n","import type { Catalogs } from './catalog';\nimport type { ResolvedConfig } from './config';\nimport { collectParams } from './params';\n\nexport interface TranslateRequest {\n sourceLocale: string;\n targetLocale: string;\n messages: Record<string, string>;\n}\n\nexport type TranslateProvider = (request: TranslateRequest) => Promise<Record<string, string>>;\n\nexport interface TranslateOptions {\n locales?: string[];\n batchSize?: number;\n dryRun?: boolean;\n}\n\nexport interface TranslateResult {\n translated: Record<string, string[]>;\n invalid: Record<string, string[]>;\n pending: Record<string, string[]>;\n}\n\n// fills '' entries via the provider; invalid translations stay '' (check keeps failing)\nexport async function translateCatalogs(\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n provider: TranslateProvider,\n options: TranslateOptions = {},\n): Promise<TranslateResult> {\n const batchSize = options.batchSize ?? 20;\n const targets = (options.locales ?? cfg.locales).filter(\n (locale) => locale !== cfg.sourceLocale && cfg.locales.includes(locale),\n );\n const source = catalogs[cfg.sourceLocale] ?? {};\n const result: TranslateResult = { translated: {}, invalid: {}, pending: {} };\n\n for (const locale of targets) {\n const catalog = (catalogs[locale] ??= {});\n const missing = Object.keys(source).filter((key) => source[key] && !catalog[key]);\n if (missing.length === 0) continue;\n\n if (options.dryRun) {\n result.pending[locale] = missing;\n continue;\n }\n\n for (let i = 0; i < missing.length; i += batchSize) {\n const keys = missing.slice(i, i + batchSize);\n const messages = Object.fromEntries(keys.map((key) => [key, source[key]!]));\n const out = await provider({\n sourceLocale: cfg.sourceLocale,\n targetLocale: locale,\n messages,\n });\n for (const key of keys) {\n const text = out[key];\n if (typeof text === 'string' && text.trim() && structureMatches(source[key]!, text)) {\n catalog[key] = text;\n (result.translated[locale] ??= []).push(key);\n } else {\n (result.invalid[locale] ??= []).push(key);\n }\n }\n }\n }\n return result;\n}\n\n// params and tags must survive translation verbatim\nexport function structureMatches(source: string, translated: string): boolean {\n return sameMembers(paramNames(source), paramNames(translated)) && sameMembers(tagTokens(source), tagTokens(translated));\n}\n\nfunction paramNames(message: string): string[] {\n try {\n return [...collectParams(message).keys()].sort();\n } catch {\n return ['\u0000invalid'];\n }\n}\n\nconst TAG = /<(\\/?)([a-zA-Z][\\w-]*)(\\/?)>/g;\n\nfunction tagTokens(message: string): string[] {\n const out: string[] = [];\n for (const match of message.matchAll(TAG)) {\n out.push(`${match[1]}${match[2]}${match[3]}`);\n }\n return out.sort();\n}\n\nfunction sameMembers(a: string[], b: string[]): boolean {\n return a.length === b.length && a.every((value, i) => value === b[i]);\n}\n"],"mappings":"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","names":["parseArgs","writeFileSync","join","writeFileSync","join","readFileSync","join","readFileSync","parse","parse","built","text","visit","readFileSync","mkdirSync","readFileSync","writeFileSync","join","glob","join","glob","readFileSync","mkdirSync","writeFileSync","parseArgs"]}
package/dist/index.d.ts CHANGED
@@ -33,6 +33,30 @@ interface Analysis {
33
33
  }
34
34
  declare function analyze(code: string, file: string): Analysis;
35
35
 
36
+ interface TranslateRequest {
37
+ sourceLocale: string;
38
+ targetLocale: string;
39
+ messages: Record<string, string>;
40
+ }
41
+ type TranslateProvider = (request: TranslateRequest) => Promise<Record<string, string>>;
42
+ interface TranslateOptions {
43
+ locales?: string[];
44
+ batchSize?: number;
45
+ dryRun?: boolean;
46
+ }
47
+ interface TranslateResult {
48
+ translated: Record<string, string[]>;
49
+ invalid: Record<string, string[]>;
50
+ pending: Record<string, string[]>;
51
+ }
52
+ declare function translateCatalogs(cfg: ResolvedConfig, catalogs: Catalogs, provider: TranslateProvider, options?: TranslateOptions): Promise<TranslateResult>;
53
+ declare function structureMatches(source: string, translated: string): boolean;
54
+
55
+ interface TranslateConfig {
56
+ provider?: 'claude' | TranslateProvider;
57
+ model?: string;
58
+ batchSize?: number;
59
+ }
36
60
  interface VerbalyConfig {
37
61
  root?: string;
38
62
  dir?: string;
@@ -40,6 +64,7 @@ interface VerbalyConfig {
40
64
  locales?: string[];
41
65
  include?: string[];
42
66
  exclude?: string[];
67
+ translate?: TranslateConfig;
43
68
  }
44
69
  interface ResolvedConfig {
45
70
  root: string;
@@ -48,6 +73,7 @@ interface ResolvedConfig {
48
73
  locales: string[];
49
74
  include: string[];
50
75
  exclude: string[];
76
+ translate: TranslateConfig;
51
77
  }
52
78
  declare function resolveConfig(config?: VerbalyConfig): ResolvedConfig;
53
79
  declare function loadConfigFile(root: string): Promise<VerbalyConfig>;
@@ -105,10 +131,47 @@ type ParamType = 'number' | 'string' | 'date' | 'unknown';
105
131
  declare function collectParams(message: string): Map<string, Set<ParamType>>;
106
132
  declare function renderParamType(types: Set<ParamType>): string;
107
133
 
134
+ interface ClaudeProviderOptions {
135
+ model?: string;
136
+ apiKey?: string;
137
+ maxTokens?: number;
138
+ }
139
+ declare function claudeProvider(options?: ClaudeProviderOptions): TranslateProvider;
140
+
141
+ declare const PSEUDO_LOCALE = "en-XA";
142
+ declare function pseudoLocalize(message: string): string;
143
+ declare function pseudoCatalogs(cfg: ResolvedConfig, catalogs: Catalogs, locale?: string): string[];
144
+
145
+ interface RenderHtmlOptions {
146
+ locale: string;
147
+ catalogs: Catalogs;
148
+ sourceLocale?: string;
149
+ attribute?: string;
150
+ richTags?: string[];
151
+ setLang?: boolean;
152
+ }
153
+ interface RenderHtmlResult {
154
+ html: string;
155
+ missing: string[];
156
+ }
157
+ declare function renderHtml(html: string, options: RenderHtmlOptions): RenderHtmlResult;
158
+ interface RenderSiteOptions {
159
+ site?: string;
160
+ locales?: string[];
161
+ attribute?: string;
162
+ richTags?: string[];
163
+ }
164
+ interface RenderSiteResult {
165
+ files: number;
166
+ locales: string[];
167
+ missing: Record<string, string[]>;
168
+ }
169
+ declare function renderSite(cfg: ResolvedConfig, options?: RenderSiteOptions): Promise<RenderSiteResult>;
170
+
108
171
  interface TransformResult {
109
172
  code: string;
110
173
  map: ReturnType<MagicString['generateMap']>;
111
174
  }
112
175
  declare function transformCode(code: string, file: string, analysis?: Analysis): TransformResult | null;
113
176
 
114
- export { type Analysis, type Catalog, type Catalogs, type CheckResult, MessageRegistry, type MissingEntry, type ParamType, type ResolvedConfig, type SyncResult, type TaggedMessage, type TaggedParam, type TransComponent, type TransformResult, type UnknownEntry, type UsedKey, VIRTUAL_ID, type VerbalyConfig, analyze, catalogPath, check, collectParams, extractProject, formatCheckResult, generateDts, generateLocaleModule, generateRuntimeModule, loadCatalogs, loadConfig, loadConfigFile, pruneCatalogs, readCatalog, renderParamType, resolveConfig, serializeCatalog, stableKey, syncCatalogs, transformCode, writeCatalog, writeDts };
177
+ export { type Analysis, type Catalog, type Catalogs, type CheckResult, type ClaudeProviderOptions, MessageRegistry, type MissingEntry, PSEUDO_LOCALE, type ParamType, type RenderHtmlOptions, type RenderHtmlResult, type RenderSiteOptions, type RenderSiteResult, type ResolvedConfig, type SyncResult, type TaggedMessage, type TaggedParam, type TransComponent, type TransformResult, type TranslateConfig, type TranslateOptions, type TranslateProvider, type TranslateRequest, type TranslateResult, type UnknownEntry, type UsedKey, VIRTUAL_ID, type VerbalyConfig, analyze, catalogPath, check, claudeProvider, collectParams, extractProject, formatCheckResult, generateDts, generateLocaleModule, generateRuntimeModule, loadCatalogs, loadConfig, loadConfigFile, pruneCatalogs, pseudoCatalogs, pseudoLocalize, readCatalog, renderHtml, renderParamType, renderSite, resolveConfig, serializeCatalog, stableKey, structureMatches, syncCatalogs, transformCode, translateCatalogs, writeCatalog, writeDts };