@devcoda/lokal-cli 1.3.5 → 1.3.6

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.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js CHANGED
@@ -326,7 +326,25 @@ async function wrapCommand(options) {
326
326
  totalStrings += result.wrapped.length;
327
327
  }
328
328
  }
329
- spinner.succeed(import_chalk4.default.green(`Found ${import_chalk4.default.bold(totalStrings)} strings to wrap in ${import_chalk4.default.bold(results.modifiedFiles)} files`));
329
+ if (results.skipped && results.skipped.length > 0) {
330
+ console.log(import_chalk4.default.bold("\n\u26A0 Skipped (already wrapped):"));
331
+ for (const file of results.skipped.slice(0, 5)) {
332
+ console.log(import_chalk4.default.gray(` ${path4.relative(projectRoot, file)}`));
333
+ }
334
+ if (results.skipped.length > 5) {
335
+ console.log(import_chalk4.default.gray(` ... and ${results.skipped.length - 5} more`));
336
+ }
337
+ }
338
+ if (results.errors && results.errors.length > 0) {
339
+ console.log(import_chalk4.default.bold("\n\u26A0 Errors:"));
340
+ for (const error of results.errors.slice(0, 5)) {
341
+ console.log(import_chalk4.default.red(` ${error}`));
342
+ }
343
+ if (results.errors.length > 5) {
344
+ console.log(import_chalk4.default.red(` ... and ${results.errors.length - 5} more`));
345
+ }
346
+ }
347
+ spinner.succeed(import_chalk4.default.green(`Found ${import_chalk4.default.bold(totalStrings)} strings to wrap in ${import_chalk4.default.bold(fileResults.length)} files`));
330
348
  if (totalStrings === 0) {
331
349
  spinner.info(import_chalk4.default.gray("No strings found that need wrapping."));
332
350
  return;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/commands/scan.ts","../src/commands/translate.ts","../src/commands/wrap.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { registerInitCommand } from './commands/init';\nimport { registerScanCommand } from './commands/scan';\nimport { registerTranslateCommand } from './commands/translate';\nimport { registerWrapCommand } from './commands/wrap';\n\nconst program = new Command();\n\nprogram\n .name('lokal')\n .description('AI-powered localization ecosystem for React and React Native')\n .version('1.0.0');\n\n// Register commands\nregisterInitCommand(program);\nregisterScanCommand(program);\nregisterTranslateCommand(program);\nregisterWrapCommand(program);\n\n// Global options\nprogram\n .option('-v, --verbose', 'Verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n process.env.LOKAL_VERBOSE = 'true';\n }\n });\n\n// Handle unknown commands\nprogram.on('command:*', () => {\n console.error(chalk.red(`Invalid command: ${program.args.join(' ')}`));\n console.log(chalk.gray(`See ${chalk.cyan('--help')} for a list of available commands.`));\n process.exit(1);\n});\n\n// Run the program\nprogram.parse(process.argv);\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\n\ninterface InitOptions {\n locales?: string;\n defaultLocale?: string;\n force?: boolean;\n}\n\n/**\n * Create the initial lokal config file and directory structure\n */\nexport async function initCommand(options: InitOptions): Promise<void> {\n const spinner = ora('Initializing LOKAL...').start();\n\n try {\n const projectRoot = process.cwd();\n const configPath = path.join(projectRoot, 'lokal.config.js');\n const localesDir = path.join(projectRoot, 'locales');\n\n // Parse locales\n const locales = options.locales\n ? options.locales.split(',').map(l => l.trim())\n : ['en'];\n\n const defaultLocale = options.defaultLocale || locales[0];\n\n // Check if already initialized\n if (fs.existsSync(configPath) && !options.force) {\n spinner.warn(chalk.yellow('LOKAL is already initialized. Use --force to reinitialize.'));\n return;\n }\n\n // Create config file\n const configContent = `module.exports = {\n // Supported locales\n locales: ${JSON.stringify(locales)},\n \n // Default locale\n defaultLocale: '${defaultLocale}',\n \n // Function name for translations (t(\"key\"))\n functionName: 't',\n \n // Component name for translations (<T>key</T>)\n componentName: 'T',\n \n // Source directory to scan\n sourceDir: './src',\n \n // Output directory for locale files\n outputDir: './locales',\n \n // AI Translation settings (optional)\n // ai: {\n // provider: 'openai', // or 'gemini'\n // apiKey: process.env.OPENAI_API_KEY,\n // model: 'gpt-4'\n // }\n};\n`;\n\n fs.writeFileSync(configPath, configContent, 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold('lokal.config.js')}`));\n\n // Create locales directory with default locale\n if (!fs.existsSync(localesDir)) {\n fs.mkdirSync(localesDir, { recursive: true });\n }\n\n // Create default locale file\n const defaultLocalePath = path.join(localesDir, `${defaultLocale}.json`);\n if (!fs.existsSync(defaultLocalePath)) {\n const initialData = {\n _meta: {\n generated: new Date().toISOString(),\n description: 'Default locale file'\n }\n };\n fs.writeFileSync(defaultLocalePath, JSON.stringify(initialData, null, 2), 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n }\n\n // Create .gitignore entry for locale files if .gitignore exists\n const gitignorePath = path.join(projectRoot, '.gitignore');\n if (fs.existsSync(gitignorePath)) {\n const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');\n if (!gitignoreContent.includes('/locales/')) {\n fs.appendFileSync(gitignorePath, '\\n# LOKAL translations\\nlocales/\\n');\n spinner.succeed(chalk.green('Updated .gitignore'));\n }\n }\n\n console.log(chalk.bold('\\n✓ LOKAL initialized successfully!'));\n console.log(chalk.gray('\\nNext steps:'));\n console.log(chalk.gray(' 1. Add translation strings to your code using t(\"key\") or <T>key</T>'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal scan') + chalk.gray(' to extract strings'));\n console.log(chalk.gray(' 3. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate with AI'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Failed to initialize: ${error}`));\n process.exit(1);\n }\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('init')\n .description('Initialize LOKAL in your project')\n .option('-l, --locales <locales>', 'Comma-separated list of locales', 'en')\n .option('-d, --default-locale <locale>', 'Default locale', 'en')\n .option('-f, --force', 'Force reinitialization', false)\n .action(initCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTParser, ConfigLoader, FileStorage, type ExtractedString } from 'lokal-core';\n\ninterface ScanOptions {\n config?: string;\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Scan source files for translation strings and update locale files\n */\nexport async function scanCommand(options: ScanOptions): Promise<void> {\n const spinner = ora('Scanning for translation strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n const sourceDir = path.resolve(projectRoot, config.sourceDir);\n const outputDir = options.output\n ? path.resolve(projectRoot, options.output)\n : path.resolve(projectRoot, config.outputDir);\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)}...`;\n\n // Create parser\n const parser = new ASTParser({\n filePath: sourceDir,\n functionName: config.functionName,\n componentName: config.componentName,\n });\n\n // Scan directory\n const result = parser.scanDirectory(sourceDir);\n\n if (result.errors.length > 0 && options.verbose) {\n for (const error of result.errors) {\n spinner.warn(chalk.yellow(error));\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(result.strings.length)} translation strings`));\n\n if (result.strings.length === 0) {\n spinner.info(chalk.gray('No strings found. Make sure to use t(\"key\") or <T>key</T> in your code.'));\n return;\n }\n\n // Create storage\n const storage = new FileStorage(outputDir);\n\n // Create unique key-value map\n const uniqueStrings = new Map<string, ExtractedString>();\n for (const str of result.strings) {\n uniqueStrings.set(str.key, str);\n }\n\n // Get the default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n\n // Merge with existing keys\n let existingData: Record<string, any> = {};\n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Convert extracted strings to flat key-value object\n const newData: Record<string, string> = {};\n for (const [key, value] of uniqueStrings) {\n // Use the key itself as the translation value for now\n newData[key] = existingData[key] || value.value;\n }\n\n // Save the merged data\n const mergedData = storage.mergeLocaleData(defaultLocale, newData);\n storage.saveLocale(defaultLocale, mergedData);\n\n spinner.succeed(chalk.green(`Updated ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n\n // Show sample of extracted strings\n if (options.verbose) {\n console.log(chalk.bold('\\nExtracted strings:'));\n const sampleKeys = Array.from(uniqueStrings.keys()).slice(0, 10);\n for (const key of sampleKeys) {\n console.log(chalk.gray(` • ${key}`));\n }\n if (uniqueStrings.size > 10) {\n console.log(chalk.gray(` ... and ${uniqueStrings.size - 10} more`));\n }\n }\n\n // Check for other locales that need translation\n const locales = storage.getAvailableLocales();\n const otherLocales = locales.filter(l => l !== defaultLocale);\n\n if (otherLocales.length > 0) {\n console.log(chalk.gray(`\\nOther locales detected: ${otherLocales.join(', ')}`));\n console.log(chalk.gray('Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate missing strings'));\n }\n\n } catch (error) {\n spinner.fail(chalk.red(`Scan failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerScanCommand(program: Command): void {\n program\n .command('scan')\n .description('Scan source files for translation strings')\n .option('-c, --config <path>', 'Path to config file')\n .option('-o, --output <path>', 'Output directory for locale files')\n .option('-v, --verbose', 'Verbose output', false)\n .action(scanCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport {\n ConfigLoader,\n FileStorage,\n AITranslator,\n TranslationProviderFactory,\n type LocaleData\n} from 'lokal-core';\n\ninterface TranslateOptions {\n config?: string;\n locale?: string;\n all?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Translate missing strings using AI\n */\nexport async function translateCommand(options: TranslateOptions): Promise<void> {\n const spinner = ora('Loading configuration...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n // Check if AI is configured\n if (!config.ai) {\n spinner.fail(chalk.red('AI provider not configured. Add ai configuration to lokal.config.js'));\n console.log(chalk.gray('\\nExample configuration:'));\n console.log(chalk.gray(' ai: {'));\n console.log(chalk.gray(' provider: \"openai\",'));\n console.log(chalk.gray(' apiKey: process.env.OPENAI_API_KEY'));\n console.log(chalk.gray(' }'));\n process.exit(1);\n }\n\n const apiKey = config.ai.apiKey || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY;\n if (!apiKey) {\n spinner.fail(chalk.red('No API key found. Set ai.apiKey in config or environment variable.'));\n process.exit(1);\n }\n\n spinner.text = 'Initializing AI translator...';\n\n // Create provider\n const provider = TranslationProviderFactory.create(\n config.ai.provider,\n apiKey,\n config.ai.model\n );\n\n // Create translator\n const translator = new AITranslator(provider);\n\n const projectRoot = process.cwd();\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n\n spinner.succeed('AI translator ready');\n\n // Determine which locales to translate\n let targetLocales: string[] = [];\n const availableLocales = config.locales || [];\n\n if (options.all) {\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale);\n } else if (options.locale) {\n targetLocales = [options.locale];\n } else {\n // Default: translate to first non-default locale\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale).slice(0, 1);\n }\n\n if (targetLocales.length === 0) {\n spinner.warn(chalk.yellow('No target locales to translate. Add more locales to your config.'));\n return;\n }\n\n // Load source locale data\n const sourceLocale = config.defaultLocale;\n const sourceData = storage.loadLocale(sourceLocale);\n\n if (!sourceData) {\n spinner.fail(chalk.red(`Source locale ${sourceLocale} not found. Run 'lokal scan' first.`));\n process.exit(1);\n }\n\n // Translate to each target locale\n for (const targetLocale of targetLocales) {\n const translateSpinner = ora(`Translating to ${chalk.cyan(targetLocale)}...`).start();\n\n // Load existing target data (if any)\n const targetLocaleFile = storage.loadLocale(targetLocale);\n const targetData: LocaleData = targetLocaleFile ? targetLocaleFile.data : {};\n\n // Translate missing keys\n const translatedData = await translator.translateMissingKeys(\n sourceData.data,\n targetData,\n sourceLocale,\n targetLocale\n );\n\n // Save translated data\n storage.saveLocale(targetLocale, translatedData);\n\n translateSpinner.succeed(chalk.green(`Translated to ${chalk.bold(targetLocale)}`));\n\n if (options.verbose) {\n // Show sample translations\n const keys = Object.keys(translatedData).slice(0, 5);\n for (const key of keys) {\n const value = translatedData[key];\n if (typeof value === 'string') {\n console.log(chalk.gray(` ${key}: ${value}`));\n }\n }\n }\n }\n\n console.log(chalk.bold('\\n✓ Translation complete!'));\n console.log(chalk.gray(`\\nRun `) + chalk.cyan('npx lokal scan') + chalk.gray(' to see updated translations'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Translation failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerTranslateCommand(program: Command): void {\n program\n .command('translate')\n .description('Translate missing strings using AI')\n .option('-c, --config <path>', 'Path to config file')\n .option('-l, --locale <locale>', 'Specific locale to translate')\n .option('-a, --all', 'Translate all locales', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(translateCommand);\n}\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTWrapper, ConfigLoader, FileStorage, type WrappedString } from 'lokal-core';\n\ninterface WrapOptions {\n config?: string;\n src?: string;\n function?: string;\n dryRun?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Auto-wrap translatable strings in source files\n * Converts plain text to t(\"key\") calls\n */\nexport async function wrapCommand(options: WrapOptions): Promise<void> {\n const spinner = ora('Preparing to wrap strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n \n // Determine source directory\n const sourceDir = options.src\n ? path.resolve(projectRoot, options.src)\n : path.resolve(projectRoot, config.sourceDir);\n\n // Check if source directory exists\n if (!fs.existsSync(sourceDir)) {\n spinner.fail(chalk.red(`Source directory not found: ${sourceDir}`));\n process.exit(1);\n }\n\n // Create wrapper\n const wrapper = new ASTWrapper({\n functionName: options.function || config.functionName || 't',\n componentName: config.componentName || 'T',\n });\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)} for translatable strings...`;\n\n // First pass: collect all wrapped strings without modifying\n const results = wrapper.wrapDirectory(sourceDir, ['.js', '.jsx', '.ts', '.tsx'], true);\n \n // Count total strings to wrap\n let totalStrings = 0;\n const fileResults: { file: string, wrapped: WrappedString[] }[] = [];\n \n for (const result of results.results) {\n if (result.wrapped.length > 0) {\n fileResults.push({\n file: result.file,\n wrapped: result.wrapped\n });\n totalStrings += result.wrapped.length;\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(totalStrings)} strings to wrap in ${chalk.bold(results.modifiedFiles)} files`));\n\n if (totalStrings === 0) {\n spinner.info(chalk.gray('No strings found that need wrapping.'));\n return;\n }\n\n // Show preview\n if (!options.dryRun) {\n console.log(chalk.bold('\\nPreview (first 10 files):'));\n let count = 0;\n for (const fileResult of fileResults.slice(0, 10)) {\n console.log(chalk.cyan(`\\n${path.relative(projectRoot, fileResult.file)}:`));\n for (const wrapped of fileResult.wrapped.slice(0, 5)) {\n console.log(chalk.gray(` \"${wrapped.original}\" → ${wrapped.wrapped}`));\n count++;\n }\n if (fileResult.wrapped.length > 5) {\n console.log(chalk.gray(` ... and ${fileResult.wrapped.length - 5} more`));\n }\n }\n if (fileResults.length > 10) {\n console.log(chalk.gray(`\\n... and ${fileResults.length - 10} more files`));\n }\n \n console.log(chalk.bold('\\n⚠ This will modify your source files!'));\n console.log(chalk.gray('Use --dry-run to preview without making changes'));\n } else {\n // Dry run - show what would be changed\n console.log(chalk.bold('\\nDry Run - Files that would be modified:'));\n for (const fileResult of fileResults) {\n console.log(chalk.cyan(` ${path.relative(projectRoot, fileResult.file)}`) + \n chalk.gray(` (${fileResult.wrapped.length} strings)`));\n }\n }\n\n if (options.dryRun) {\n spinner.info(chalk.yellow('Dry run complete. No files were modified.'));\n return;\n }\n\n // Confirm before making changes\n const confirmSpinner = ora('Applying changes...').start();\n\n // Apply changes to each file\n let modifiedCount = 0;\n for (const fileResult of fileResults) {\n const result = wrapper.wrapFile(fileResult.file);\n if (result.modified) {\n modifiedCount++;\n }\n }\n\n confirmSpinner.succeed(chalk.green(`Modified ${chalk.bold(modifiedCount)} files`));\n\n // Also update the locale file with the new keys\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n \n // Collect all new keys\n const newKeys: Record<string, string> = {};\n for (const fileResult of fileResults) {\n for (const wrapped of fileResult.wrapped) {\n newKeys[wrapped.key] = wrapped.original;\n }\n }\n\n // Add keys to default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n let existingData: Record<string, any> = {};\n \n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Merge new keys\n const mergedData = storage.mergeLocaleData(defaultLocale, newKeys);\n storage.saveLocale(defaultLocale, mergedData);\n\n console.log(chalk.green(`\\n✓ Added ${chalk.bold(Object.keys(newKeys).length)} new keys to locales/${defaultLocale}.json`));\n\n // Show next steps\n console.log(chalk.bold('\\nNext steps:'));\n console.log(chalk.gray(' 1. Review the changes in your source files'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate to other locales'));\n \n } catch (error) {\n spinner.fail(chalk.red(`Wrap failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerWrapCommand(program: Command): void {\n program\n .command('wrap')\n .description('Automatically wrap translatable strings in source files')\n .option('-c, --config <path>', 'Path to config file')\n .option('-s, --src <path>', 'Source directory to scan')\n .option('-f, --function <name>', 'Translation function name', 't')\n .option('-d, --dry-run', 'Preview changes without modifying files', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(wrapCommand);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,uBAAwB;AACxB,IAAAA,gBAAkB;;;ACHlB,SAAoB;AACpB,WAAsB;AAEtB,mBAAkB;AAClB,iBAAgB;AAWhB,eAAsB,YAAY,SAAqC;AACnE,QAAM,cAAU,WAAAC,SAAI,uBAAuB,EAAE,MAAM;AAEnD,MAAI;AACA,UAAM,cAAc,QAAQ,IAAI;AAChC,UAAM,aAAkB,UAAK,aAAa,iBAAiB;AAC3D,UAAM,aAAkB,UAAK,aAAa,SAAS;AAGnD,UAAM,UAAU,QAAQ,UAClB,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC,IAC5C,CAAC,IAAI;AAEX,UAAM,gBAAgB,QAAQ,iBAAiB,QAAQ,CAAC;AAGxD,QAAO,cAAW,UAAU,KAAK,CAAC,QAAQ,OAAO;AAC7C,cAAQ,KAAK,aAAAC,QAAM,OAAO,4DAA4D,CAAC;AACvF;AAAA,IACJ;AAGA,UAAM,gBAAgB;AAAA;AAAA,aAEjB,KAAK,UAAU,OAAO,CAAC;AAAA;AAAA;AAAA,oBAGhB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBzB,IAAG,iBAAc,YAAY,eAAe,OAAO;AACnD,YAAQ,QAAQ,aAAAA,QAAM,MAAM,WAAW,aAAAA,QAAM,KAAK,iBAAiB,CAAC,EAAE,CAAC;AAGvE,QAAI,CAAI,cAAW,UAAU,GAAG;AAC5B,MAAG,aAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,IAChD;AAGA,UAAM,oBAAyB,UAAK,YAAY,GAAG,aAAa,OAAO;AACvE,QAAI,CAAI,cAAW,iBAAiB,GAAG;AACnC,YAAM,cAAc;AAAA,QAChB,OAAO;AAAA,UACH,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UAClC,aAAa;AAAA,QACjB;AAAA,MACJ;AACA,MAAG,iBAAc,mBAAmB,KAAK,UAAU,aAAa,MAAM,CAAC,GAAG,OAAO;AACjF,cAAQ,QAAQ,aAAAA,QAAM,MAAM,WAAW,aAAAA,QAAM,KAAK,WAAW,aAAa,OAAO,CAAC,EAAE,CAAC;AAAA,IACzF;AAGA,UAAM,gBAAqB,UAAK,aAAa,YAAY;AACzD,QAAO,cAAW,aAAa,GAAG;AAC9B,YAAM,mBAAsB,gBAAa,eAAe,OAAO;AAC/D,UAAI,CAAC,iBAAiB,SAAS,WAAW,GAAG;AACzC,QAAG,kBAAe,eAAe,oCAAoC;AACrE,gBAAQ,QAAQ,aAAAA,QAAM,MAAM,oBAAoB,CAAC;AAAA,MACrD;AAAA,IACJ;AAEA,YAAQ,IAAI,aAAAA,QAAM,KAAK,0CAAqC,CAAC;AAC7D,YAAQ,IAAI,aAAAA,QAAM,KAAK,eAAe,CAAC;AACvC,YAAQ,IAAI,aAAAA,QAAM,KAAK,wEAAwE,CAAC;AAChG,YAAQ,IAAI,aAAAA,QAAM,KAAK,WAAW,IAAI,aAAAA,QAAM,KAAK,gBAAgB,IAAI,aAAAA,QAAM,KAAK,qBAAqB,CAAC;AACtG,YAAQ,IAAI,aAAAA,QAAM,KAAK,WAAW,IAAI,aAAAA,QAAM,KAAK,qBAAqB,IAAI,aAAAA,QAAM,KAAK,uBAAuB,CAAC;AAAA,EAEjH,SAAS,OAAO;AACZ,YAAQ,KAAK,aAAAA,QAAM,IAAI,yBAAyB,KAAK,EAAE,CAAC;AACxD,YAAQ,KAAK,CAAC;AAAA,EAClB;AACJ;AAEO,SAAS,oBAAoBC,UAAwB;AACxD,EAAAA,SACK,QAAQ,MAAM,EACd,YAAY,kCAAkC,EAC9C,OAAO,2BAA2B,mCAAmC,IAAI,EACzE,OAAO,iCAAiC,kBAAkB,IAAI,EAC9D,OAAO,eAAe,0BAA0B,KAAK,EACrD,OAAO,WAAW;AAC3B;;;ACpHA,IAAAC,QAAsB;AAEtB,IAAAC,gBAAkB;AAClB,IAAAC,cAAgB;AAChB,wBAA2E;AAW3E,eAAsB,YAAY,SAAqC;AACnE,QAAM,cAAU,YAAAC,SAAI,qCAAqC,EAAE,MAAM;AAEjE,MAAI;AAEA,UAAM,eAAe,IAAI,+BAAa;AACtC,QAAI;AAEJ,QAAI,QAAQ,QAAQ;AAChB,eAAS,aAAa,SAAS,QAAQ,MAAM;AAAA,IACjD,OAAO;AACH,eAAS,MAAM,aAAa,KAAK;AAAA,IACrC;AAEA,UAAM,cAAc,QAAQ,IAAI;AAChC,UAAM,YAAiB,cAAQ,aAAa,OAAO,SAAS;AAC5D,UAAM,YAAY,QAAQ,SACf,cAAQ,aAAa,QAAQ,MAAM,IACnC,cAAQ,aAAa,OAAO,SAAS;AAEhD,YAAQ,OAAO,YAAY,cAAAC,QAAM,KAAK,SAAS,CAAC;AAGhD,UAAM,SAAS,IAAI,4BAAU;AAAA,MACzB,UAAU;AAAA,MACV,cAAc,OAAO;AAAA,MACrB,eAAe,OAAO;AAAA,IAC1B,CAAC;AAGD,UAAM,SAAS,OAAO,cAAc,SAAS;AAE7C,QAAI,OAAO,OAAO,SAAS,KAAK,QAAQ,SAAS;AAC7C,iBAAW,SAAS,OAAO,QAAQ;AAC/B,gBAAQ,KAAK,cAAAA,QAAM,OAAO,KAAK,CAAC;AAAA,MACpC;AAAA,IACJ;AAEA,YAAQ,QAAQ,cAAAA,QAAM,MAAM,SAAS,cAAAA,QAAM,KAAK,OAAO,QAAQ,MAAM,CAAC,sBAAsB,CAAC;AAE7F,QAAI,OAAO,QAAQ,WAAW,GAAG;AAC7B,cAAQ,KAAK,cAAAA,QAAM,KAAK,yEAAyE,CAAC;AAClG;AAAA,IACJ;AAGA,UAAM,UAAU,IAAI,8BAAY,SAAS;AAGzC,UAAM,gBAAgB,oBAAI,IAA6B;AACvD,eAAW,OAAO,OAAO,SAAS;AAC9B,oBAAc,IAAI,IAAI,KAAK,GAAG;AAAA,IAClC;AAGA,UAAM,gBAAgB,OAAO;AAC7B,UAAM,iBAAiB,QAAQ,WAAW,aAAa;AAGvD,QAAI,eAAoC,CAAC;AACzC,QAAI,gBAAgB;AAChB,qBAAe,eAAe;AAAA,IAClC;AAGA,UAAM,UAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,eAAe;AAEtC,cAAQ,GAAG,IAAI,aAAa,GAAG,KAAK,MAAM;AAAA,IAC9C;AAGA,UAAM,aAAa,QAAQ,gBAAgB,eAAe,OAAO;AACjE,YAAQ,WAAW,eAAe,UAAU;AAE5C,YAAQ,QAAQ,cAAAA,QAAM,MAAM,WAAW,cAAAA,QAAM,KAAK,WAAW,aAAa,OAAO,CAAC,EAAE,CAAC;AAGrF,QAAI,QAAQ,SAAS;AACjB,cAAQ,IAAI,cAAAA,QAAM,KAAK,sBAAsB,CAAC;AAC9C,YAAM,aAAa,MAAM,KAAK,cAAc,KAAK,CAAC,EAAE,MAAM,GAAG,EAAE;AAC/D,iBAAW,OAAO,YAAY;AAC1B,gBAAQ,IAAI,cAAAA,QAAM,KAAK,YAAO,GAAG,EAAE,CAAC;AAAA,MACxC;AACA,UAAI,cAAc,OAAO,IAAI;AACzB,gBAAQ,IAAI,cAAAA,QAAM,KAAK,aAAa,cAAc,OAAO,EAAE,OAAO,CAAC;AAAA,MACvE;AAAA,IACJ;AAGA,UAAM,UAAU,QAAQ,oBAAoB;AAC5C,UAAM,eAAe,QAAQ,OAAO,OAAK,MAAM,aAAa;AAE5D,QAAI,aAAa,SAAS,GAAG;AACzB,cAAQ,IAAI,cAAAA,QAAM,KAAK;AAAA,0BAA6B,aAAa,KAAK,IAAI,CAAC,EAAE,CAAC;AAC9E,cAAQ,IAAI,cAAAA,QAAM,KAAK,MAAM,IAAI,cAAAA,QAAM,KAAK,qBAAqB,IAAI,cAAAA,QAAM,KAAK,+BAA+B,CAAC;AAAA,IACpH;AAAA,EAEJ,SAAS,OAAO;AACZ,YAAQ,KAAK,cAAAA,QAAM,IAAI,gBAAgB,KAAK,EAAE,CAAC;AAC/C,QAAI,QAAQ,SAAS;AACjB,cAAQ,MAAM,KAAK;AAAA,IACvB;AACA,YAAQ,KAAK,CAAC;AAAA,EAClB;AACJ;AAEO,SAAS,oBAAoBC,UAAwB;AACxD,EAAAA,SACK,QAAQ,MAAM,EACd,YAAY,2CAA2C,EACvD,OAAO,uBAAuB,qBAAqB,EACnD,OAAO,uBAAuB,mCAAmC,EACjE,OAAO,iBAAiB,kBAAkB,KAAK,EAC/C,OAAO,WAAW;AAC3B;;;AClIA,IAAAC,QAAsB;AAEtB,IAAAC,gBAAkB;AAClB,IAAAC,cAAgB;AAChB,IAAAC,qBAMO;AAYP,eAAsB,iBAAiB,SAA0C;AAC7E,QAAM,cAAU,YAAAC,SAAI,0BAA0B,EAAE,MAAM;AAEtD,MAAI;AAEA,UAAM,eAAe,IAAI,gCAAa;AACtC,QAAI;AAEJ,QAAI,QAAQ,QAAQ;AAChB,eAAS,aAAa,SAAS,QAAQ,MAAM;AAAA,IACjD,OAAO;AACH,eAAS,MAAM,aAAa,KAAK;AAAA,IACrC;AAGA,QAAI,CAAC,OAAO,IAAI;AACZ,cAAQ,KAAK,cAAAC,QAAM,IAAI,qEAAqE,CAAC;AAC7F,cAAQ,IAAI,cAAAA,QAAM,KAAK,0BAA0B,CAAC;AAClD,cAAQ,IAAI,cAAAA,QAAM,KAAK,SAAS,CAAC;AACjC,cAAQ,IAAI,cAAAA,QAAM,KAAK,yBAAyB,CAAC;AACjD,cAAQ,IAAI,cAAAA,QAAM,KAAK,wCAAwC,CAAC;AAChE,cAAQ,IAAI,cAAAA,QAAM,KAAK,KAAK,CAAC;AAC7B,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,UAAM,SAAS,OAAO,GAAG,UAAU,QAAQ,IAAI,kBAAkB,QAAQ,IAAI;AAC7E,QAAI,CAAC,QAAQ;AACT,cAAQ,KAAK,cAAAA,QAAM,IAAI,oEAAoE,CAAC;AAC5F,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,YAAQ,OAAO;AAGf,UAAM,WAAW,8CAA2B;AAAA,MACxC,OAAO,GAAG;AAAA,MACV;AAAA,MACA,OAAO,GAAG;AAAA,IACd;AAGA,UAAM,aAAa,IAAI,gCAAa,QAAQ;AAE5C,UAAM,cAAc,QAAQ,IAAI;AAChC,UAAM,YAAiB,cAAQ,aAAa,OAAO,SAAS;AAC5D,UAAM,UAAU,IAAI,+BAAY,SAAS;AAEzC,YAAQ,QAAQ,qBAAqB;AAGrC,QAAI,gBAA0B,CAAC;AAC/B,UAAM,mBAAmB,OAAO,WAAW,CAAC;AAE5C,QAAI,QAAQ,KAAK;AACb,sBAAgB,iBAAiB,OAAO,OAAK,MAAM,OAAO,aAAa;AAAA,IAC3E,WAAW,QAAQ,QAAQ;AACvB,sBAAgB,CAAC,QAAQ,MAAM;AAAA,IACnC,OAAO;AAEH,sBAAgB,iBAAiB,OAAO,OAAK,MAAM,OAAO,aAAa,EAAE,MAAM,GAAG,CAAC;AAAA,IACvF;AAEA,QAAI,cAAc,WAAW,GAAG;AAC5B,cAAQ,KAAK,cAAAA,QAAM,OAAO,kEAAkE,CAAC;AAC7F;AAAA,IACJ;AAGA,UAAM,eAAe,OAAO;AAC5B,UAAM,aAAa,QAAQ,WAAW,YAAY;AAElD,QAAI,CAAC,YAAY;AACb,cAAQ,KAAK,cAAAA,QAAM,IAAI,iBAAiB,YAAY,qCAAqC,CAAC;AAC1F,cAAQ,KAAK,CAAC;AAAA,IAClB;AAGA,eAAW,gBAAgB,eAAe;AACtC,YAAM,uBAAmB,YAAAD,SAAI,kBAAkB,cAAAC,QAAM,KAAK,YAAY,CAAC,KAAK,EAAE,MAAM;AAGpF,YAAM,mBAAmB,QAAQ,WAAW,YAAY;AACxD,YAAM,aAAyB,mBAAmB,iBAAiB,OAAO,CAAC;AAG3E,YAAM,iBAAiB,MAAM,WAAW;AAAA,QACpC,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAGA,cAAQ,WAAW,cAAc,cAAc;AAE/C,uBAAiB,QAAQ,cAAAA,QAAM,MAAM,iBAAiB,cAAAA,QAAM,KAAK,YAAY,CAAC,EAAE,CAAC;AAEjF,UAAI,QAAQ,SAAS;AAEjB,cAAM,OAAO,OAAO,KAAK,cAAc,EAAE,MAAM,GAAG,CAAC;AACnD,mBAAW,OAAO,MAAM;AACpB,gBAAM,QAAQ,eAAe,GAAG;AAChC,cAAI,OAAO,UAAU,UAAU;AAC3B,oBAAQ,IAAI,cAAAA,QAAM,KAAK,KAAK,GAAG,KAAK,KAAK,EAAE,CAAC;AAAA,UAChD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,YAAQ,IAAI,cAAAA,QAAM,KAAK,gCAA2B,CAAC;AACnD,YAAQ,IAAI,cAAAA,QAAM,KAAK;AAAA,KAAQ,IAAI,cAAAA,QAAM,KAAK,gBAAgB,IAAI,cAAAA,QAAM,KAAK,8BAA8B,CAAC;AAAA,EAEhH,SAAS,OAAO;AACZ,YAAQ,KAAK,cAAAA,QAAM,IAAI,uBAAuB,KAAK,EAAE,CAAC;AACtD,QAAI,QAAQ,SAAS;AACjB,cAAQ,MAAM,KAAK;AAAA,IACvB;AACA,YAAQ,KAAK,CAAC;AAAA,EAClB;AACJ;AAEO,SAAS,yBAAyBC,UAAwB;AAC7D,EAAAA,SACK,QAAQ,WAAW,EACnB,YAAY,oCAAoC,EAChD,OAAO,uBAAuB,qBAAqB,EACnD,OAAO,yBAAyB,8BAA8B,EAC9D,OAAO,aAAa,yBAAyB,KAAK,EAClD,OAAO,iBAAiB,kBAAkB,KAAK,EAC/C,OAAO,gBAAgB;AAChC;;;ACxJA,IAAAC,QAAsB;AACtB,IAAAC,MAAoB;AAEpB,IAAAC,gBAAkB;AAClB,IAAAC,cAAgB;AAChB,IAAAC,qBAA0E;AAc1E,eAAsB,YAAY,SAAqC;AACnE,QAAM,cAAU,YAAAC,SAAI,8BAA8B,EAAE,MAAM;AAE1D,MAAI;AAEA,UAAM,eAAe,IAAI,gCAAa;AACtC,QAAI;AAEJ,QAAI,QAAQ,QAAQ;AAChB,eAAS,aAAa,SAAS,QAAQ,MAAM;AAAA,IACjD,OAAO;AACH,eAAS,MAAM,aAAa,KAAK;AAAA,IACrC;AAEA,UAAM,cAAc,QAAQ,IAAI;AAGhC,UAAM,YAAY,QAAQ,MACf,cAAQ,aAAa,QAAQ,GAAG,IAChC,cAAQ,aAAa,OAAO,SAAS;AAGhD,QAAI,CAAI,eAAW,SAAS,GAAG;AAC3B,cAAQ,KAAK,cAAAC,QAAM,IAAI,+BAA+B,SAAS,EAAE,CAAC;AAClE,cAAQ,KAAK,CAAC;AAAA,IAClB;AAGA,UAAM,UAAU,IAAI,8BAAW;AAAA,MAC3B,cAAc,QAAQ,YAAY,OAAO,gBAAgB;AAAA,MACzD,eAAe,OAAO,iBAAiB;AAAA,IAC3C,CAAC;AAED,YAAQ,OAAO,YAAY,cAAAA,QAAM,KAAK,SAAS,CAAC;AAGhD,UAAM,UAAU,QAAQ,cAAc,WAAW,CAAC,OAAO,QAAQ,OAAO,MAAM,GAAG,IAAI;AAGrF,QAAI,eAAe;AACnB,UAAM,cAA4D,CAAC;AAEnE,eAAW,UAAU,QAAQ,SAAS;AAClC,UAAI,OAAO,QAAQ,SAAS,GAAG;AAC3B,oBAAY,KAAK;AAAA,UACb,MAAM,OAAO;AAAA,UACb,SAAS,OAAO;AAAA,QACpB,CAAC;AACD,wBAAgB,OAAO,QAAQ;AAAA,MACnC;AAAA,IACJ;AAEA,YAAQ,QAAQ,cAAAA,QAAM,MAAM,SAAS,cAAAA,QAAM,KAAK,YAAY,CAAC,uBAAuB,cAAAA,QAAM,KAAK,QAAQ,aAAa,CAAC,QAAQ,CAAC;AAE9H,QAAI,iBAAiB,GAAG;AACpB,cAAQ,KAAK,cAAAA,QAAM,KAAK,sCAAsC,CAAC;AAC/D;AAAA,IACJ;AAGA,QAAI,CAAC,QAAQ,QAAQ;AACjB,cAAQ,IAAI,cAAAA,QAAM,KAAK,6BAA6B,CAAC;AACrD,UAAI,QAAQ;AACZ,iBAAW,cAAc,YAAY,MAAM,GAAG,EAAE,GAAG;AAC/C,gBAAQ,IAAI,cAAAA,QAAM,KAAK;AAAA,EAAU,eAAS,aAAa,WAAW,IAAI,CAAC,GAAG,CAAC;AAC3E,mBAAW,WAAW,WAAW,QAAQ,MAAM,GAAG,CAAC,GAAG;AAClD,kBAAQ,IAAI,cAAAA,QAAM,KAAK,MAAM,QAAQ,QAAQ,YAAO,QAAQ,OAAO,EAAE,CAAC;AACtE;AAAA,QACJ;AACA,YAAI,WAAW,QAAQ,SAAS,GAAG;AAC/B,kBAAQ,IAAI,cAAAA,QAAM,KAAK,aAAa,WAAW,QAAQ,SAAS,CAAC,OAAO,CAAC;AAAA,QAC7E;AAAA,MACJ;AACA,UAAI,YAAY,SAAS,IAAI;AACzB,gBAAQ,IAAI,cAAAA,QAAM,KAAK;AAAA,UAAa,YAAY,SAAS,EAAE,aAAa,CAAC;AAAA,MAC7E;AAEA,cAAQ,IAAI,cAAAA,QAAM,KAAK,8CAAyC,CAAC;AACjE,cAAQ,IAAI,cAAAA,QAAM,KAAK,iDAAiD,CAAC;AAAA,IAC7E,OAAO;AAEH,cAAQ,IAAI,cAAAA,QAAM,KAAK,2CAA2C,CAAC;AACnE,iBAAW,cAAc,aAAa;AAClC,gBAAQ,IAAI,cAAAA,QAAM,KAAK,KAAU,eAAS,aAAa,WAAW,IAAI,CAAC,EAAE,IACrE,cAAAA,QAAM,KAAK,KAAK,WAAW,QAAQ,MAAM,WAAW,CAAC;AAAA,MAC7D;AAAA,IACJ;AAEA,QAAI,QAAQ,QAAQ;AAChB,cAAQ,KAAK,cAAAA,QAAM,OAAO,2CAA2C,CAAC;AACtE;AAAA,IACJ;AAGA,UAAM,qBAAiB,YAAAD,SAAI,qBAAqB,EAAE,MAAM;AAGxD,QAAI,gBAAgB;AACpB,eAAW,cAAc,aAAa;AAClC,YAAM,SAAS,QAAQ,SAAS,WAAW,IAAI;AAC/C,UAAI,OAAO,UAAU;AACjB;AAAA,MACJ;AAAA,IACJ;AAEA,mBAAe,QAAQ,cAAAC,QAAM,MAAM,YAAY,cAAAA,QAAM,KAAK,aAAa,CAAC,QAAQ,CAAC;AAGjF,UAAM,YAAiB,cAAQ,aAAa,OAAO,SAAS;AAC5D,UAAM,UAAU,IAAI,+BAAY,SAAS;AAGzC,UAAM,UAAkC,CAAC;AACzC,eAAW,cAAc,aAAa;AAClC,iBAAW,WAAW,WAAW,SAAS;AACtC,gBAAQ,QAAQ,GAAG,IAAI,QAAQ;AAAA,MACnC;AAAA,IACJ;AAGA,UAAM,gBAAgB,OAAO;AAC7B,UAAM,iBAAiB,QAAQ,WAAW,aAAa;AACvD,QAAI,eAAoC,CAAC;AAEzC,QAAI,gBAAgB;AAChB,qBAAe,eAAe;AAAA,IAClC;AAGA,UAAM,aAAa,QAAQ,gBAAgB,eAAe,OAAO;AACjE,YAAQ,WAAW,eAAe,UAAU;AAE5C,YAAQ,IAAI,cAAAA,QAAM,MAAM;AAAA,eAAa,cAAAA,QAAM,KAAK,OAAO,KAAK,OAAO,EAAE,MAAM,CAAC,wBAAwB,aAAa,OAAO,CAAC;AAGzH,YAAQ,IAAI,cAAAA,QAAM,KAAK,eAAe,CAAC;AACvC,YAAQ,IAAI,cAAAA,QAAM,KAAK,8CAA8C,CAAC;AACtE,YAAQ,IAAI,cAAAA,QAAM,KAAK,WAAW,IAAI,cAAAA,QAAM,KAAK,qBAAqB,IAAI,cAAAA,QAAM,KAAK,gCAAgC,CAAC;AAAA,EAE1H,SAAS,OAAO;AACZ,YAAQ,KAAK,cAAAA,QAAM,IAAI,gBAAgB,KAAK,EAAE,CAAC;AAC/C,QAAI,QAAQ,SAAS;AACjB,cAAQ,MAAM,KAAK;AAAA,IACvB;AACA,YAAQ,KAAK,CAAC;AAAA,EAClB;AACJ;AAEO,SAAS,oBAAoBC,UAAwB;AACxD,EAAAA,SACK,QAAQ,MAAM,EACd,YAAY,yDAAyD,EACrE,OAAO,uBAAuB,qBAAqB,EACnD,OAAO,oBAAoB,0BAA0B,EACrD,OAAO,yBAAyB,6BAA6B,GAAG,EAChE,OAAO,iBAAiB,2CAA2C,KAAK,EACxE,OAAO,iBAAiB,kBAAkB,KAAK,EAC/C,OAAO,WAAW;AAC3B;;;AJxKA,IAAM,UAAU,IAAI,yBAAQ;AAE5B,QACK,KAAK,OAAO,EACZ,YAAY,8DAA8D,EAC1E,QAAQ,OAAO;AAGpB,oBAAoB,OAAO;AAC3B,oBAAoB,OAAO;AAC3B,yBAAyB,OAAO;AAChC,oBAAoB,OAAO;AAG3B,QACK,OAAO,iBAAiB,gBAAgB,EACxC,KAAK,aAAa,CAAC,gBAAgB;AAChC,QAAM,OAAO,YAAY,KAAK;AAC9B,MAAI,KAAK,SAAS;AACd,YAAQ,IAAI,gBAAgB;AAAA,EAChC;AACJ,CAAC;AAGL,QAAQ,GAAG,aAAa,MAAM;AAC1B,UAAQ,MAAM,cAAAC,QAAM,IAAI,oBAAoB,QAAQ,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC;AACrE,UAAQ,IAAI,cAAAA,QAAM,KAAK,OAAO,cAAAA,QAAM,KAAK,QAAQ,CAAC,oCAAoC,CAAC;AACvF,UAAQ,KAAK,CAAC;AAClB,CAAC;AAGD,QAAQ,MAAM,QAAQ,IAAI;","names":["import_chalk","ora","chalk","program","path","import_chalk","import_ora","ora","chalk","program","path","import_chalk","import_ora","import_lokal_core","ora","chalk","program","path","fs","import_chalk","import_ora","import_lokal_core","ora","chalk","program","chalk"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/commands/scan.ts","../src/commands/translate.ts","../src/commands/wrap.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { registerInitCommand } from './commands/init';\nimport { registerScanCommand } from './commands/scan';\nimport { registerTranslateCommand } from './commands/translate';\nimport { registerWrapCommand } from './commands/wrap';\n\nconst program = new Command();\n\nprogram\n .name('lokal')\n .description('AI-powered localization ecosystem for React and React Native')\n .version('1.0.0');\n\n// Register commands\nregisterInitCommand(program);\nregisterScanCommand(program);\nregisterTranslateCommand(program);\nregisterWrapCommand(program);\n\n// Global options\nprogram\n .option('-v, --verbose', 'Verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n process.env.LOKAL_VERBOSE = 'true';\n }\n });\n\n// Handle unknown commands\nprogram.on('command:*', () => {\n console.error(chalk.red(`Invalid command: ${program.args.join(' ')}`));\n console.log(chalk.gray(`See ${chalk.cyan('--help')} for a list of available commands.`));\n process.exit(1);\n});\n\n// Run the program\nprogram.parse(process.argv);\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\n\ninterface InitOptions {\n locales?: string;\n defaultLocale?: string;\n force?: boolean;\n}\n\n/**\n * Create the initial lokal config file and directory structure\n */\nexport async function initCommand(options: InitOptions): Promise<void> {\n const spinner = ora('Initializing LOKAL...').start();\n\n try {\n const projectRoot = process.cwd();\n const configPath = path.join(projectRoot, 'lokal.config.js');\n const localesDir = path.join(projectRoot, 'locales');\n\n // Parse locales\n const locales = options.locales\n ? options.locales.split(',').map(l => l.trim())\n : ['en'];\n\n const defaultLocale = options.defaultLocale || locales[0];\n\n // Check if already initialized\n if (fs.existsSync(configPath) && !options.force) {\n spinner.warn(chalk.yellow('LOKAL is already initialized. Use --force to reinitialize.'));\n return;\n }\n\n // Create config file\n const configContent = `module.exports = {\n // Supported locales\n locales: ${JSON.stringify(locales)},\n \n // Default locale\n defaultLocale: '${defaultLocale}',\n \n // Function name for translations (t(\"key\"))\n functionName: 't',\n \n // Component name for translations (<T>key</T>)\n componentName: 'T',\n \n // Source directory to scan\n sourceDir: './src',\n \n // Output directory for locale files\n outputDir: './locales',\n \n // AI Translation settings (optional)\n // ai: {\n // provider: 'openai', // or 'gemini'\n // apiKey: process.env.OPENAI_API_KEY,\n // model: 'gpt-4'\n // }\n};\n`;\n\n fs.writeFileSync(configPath, configContent, 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold('lokal.config.js')}`));\n\n // Create locales directory with default locale\n if (!fs.existsSync(localesDir)) {\n fs.mkdirSync(localesDir, { recursive: true });\n }\n\n // Create default locale file\n const defaultLocalePath = path.join(localesDir, `${defaultLocale}.json`);\n if (!fs.existsSync(defaultLocalePath)) {\n const initialData = {\n _meta: {\n generated: new Date().toISOString(),\n description: 'Default locale file'\n }\n };\n fs.writeFileSync(defaultLocalePath, JSON.stringify(initialData, null, 2), 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n }\n\n // Create .gitignore entry for locale files if .gitignore exists\n const gitignorePath = path.join(projectRoot, '.gitignore');\n if (fs.existsSync(gitignorePath)) {\n const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');\n if (!gitignoreContent.includes('/locales/')) {\n fs.appendFileSync(gitignorePath, '\\n# LOKAL translations\\nlocales/\\n');\n spinner.succeed(chalk.green('Updated .gitignore'));\n }\n }\n\n console.log(chalk.bold('\\n✓ LOKAL initialized successfully!'));\n console.log(chalk.gray('\\nNext steps:'));\n console.log(chalk.gray(' 1. Add translation strings to your code using t(\"key\") or <T>key</T>'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal scan') + chalk.gray(' to extract strings'));\n console.log(chalk.gray(' 3. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate with AI'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Failed to initialize: ${error}`));\n process.exit(1);\n }\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('init')\n .description('Initialize LOKAL in your project')\n .option('-l, --locales <locales>', 'Comma-separated list of locales', 'en')\n .option('-d, --default-locale <locale>', 'Default locale', 'en')\n .option('-f, --force', 'Force reinitialization', false)\n .action(initCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTParser, ConfigLoader, FileStorage, type ExtractedString } from 'lokal-core';\n\ninterface ScanOptions {\n config?: string;\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Scan source files for translation strings and update locale files\n */\nexport async function scanCommand(options: ScanOptions): Promise<void> {\n const spinner = ora('Scanning for translation strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n const sourceDir = path.resolve(projectRoot, config.sourceDir);\n const outputDir = options.output\n ? path.resolve(projectRoot, options.output)\n : path.resolve(projectRoot, config.outputDir);\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)}...`;\n\n // Create parser\n const parser = new ASTParser({\n filePath: sourceDir,\n functionName: config.functionName,\n componentName: config.componentName,\n });\n\n // Scan directory\n const result = parser.scanDirectory(sourceDir);\n\n if (result.errors.length > 0 && options.verbose) {\n for (const error of result.errors) {\n spinner.warn(chalk.yellow(error));\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(result.strings.length)} translation strings`));\n\n if (result.strings.length === 0) {\n spinner.info(chalk.gray('No strings found. Make sure to use t(\"key\") or <T>key</T> in your code.'));\n return;\n }\n\n // Create storage\n const storage = new FileStorage(outputDir);\n\n // Create unique key-value map\n const uniqueStrings = new Map<string, ExtractedString>();\n for (const str of result.strings) {\n uniqueStrings.set(str.key, str);\n }\n\n // Get the default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n\n // Merge with existing keys\n let existingData: Record<string, any> = {};\n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Convert extracted strings to flat key-value object\n const newData: Record<string, string> = {};\n for (const [key, value] of uniqueStrings) {\n // Use the key itself as the translation value for now\n newData[key] = existingData[key] || value.value;\n }\n\n // Save the merged data\n const mergedData = storage.mergeLocaleData(defaultLocale, newData);\n storage.saveLocale(defaultLocale, mergedData);\n\n spinner.succeed(chalk.green(`Updated ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n\n // Show sample of extracted strings\n if (options.verbose) {\n console.log(chalk.bold('\\nExtracted strings:'));\n const sampleKeys = Array.from(uniqueStrings.keys()).slice(0, 10);\n for (const key of sampleKeys) {\n console.log(chalk.gray(` • ${key}`));\n }\n if (uniqueStrings.size > 10) {\n console.log(chalk.gray(` ... and ${uniqueStrings.size - 10} more`));\n }\n }\n\n // Check for other locales that need translation\n const locales = storage.getAvailableLocales();\n const otherLocales = locales.filter(l => l !== defaultLocale);\n\n if (otherLocales.length > 0) {\n console.log(chalk.gray(`\\nOther locales detected: ${otherLocales.join(', ')}`));\n console.log(chalk.gray('Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate missing strings'));\n }\n\n } catch (error) {\n spinner.fail(chalk.red(`Scan failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerScanCommand(program: Command): void {\n program\n .command('scan')\n .description('Scan source files for translation strings')\n .option('-c, --config <path>', 'Path to config file')\n .option('-o, --output <path>', 'Output directory for locale files')\n .option('-v, --verbose', 'Verbose output', false)\n .action(scanCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport {\n ConfigLoader,\n FileStorage,\n AITranslator,\n TranslationProviderFactory,\n type LocaleData\n} from 'lokal-core';\n\ninterface TranslateOptions {\n config?: string;\n locale?: string;\n all?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Translate missing strings using AI\n */\nexport async function translateCommand(options: TranslateOptions): Promise<void> {\n const spinner = ora('Loading configuration...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n // Check if AI is configured\n if (!config.ai) {\n spinner.fail(chalk.red('AI provider not configured. Add ai configuration to lokal.config.js'));\n console.log(chalk.gray('\\nExample configuration:'));\n console.log(chalk.gray(' ai: {'));\n console.log(chalk.gray(' provider: \"openai\",'));\n console.log(chalk.gray(' apiKey: process.env.OPENAI_API_KEY'));\n console.log(chalk.gray(' }'));\n process.exit(1);\n }\n\n const apiKey = config.ai.apiKey || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY;\n if (!apiKey) {\n spinner.fail(chalk.red('No API key found. Set ai.apiKey in config or environment variable.'));\n process.exit(1);\n }\n\n spinner.text = 'Initializing AI translator...';\n\n // Create provider\n const provider = TranslationProviderFactory.create(\n config.ai.provider,\n apiKey,\n config.ai.model\n );\n\n // Create translator\n const translator = new AITranslator(provider);\n\n const projectRoot = process.cwd();\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n\n spinner.succeed('AI translator ready');\n\n // Determine which locales to translate\n let targetLocales: string[] = [];\n const availableLocales = config.locales || [];\n\n if (options.all) {\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale);\n } else if (options.locale) {\n targetLocales = [options.locale];\n } else {\n // Default: translate to first non-default locale\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale).slice(0, 1);\n }\n\n if (targetLocales.length === 0) {\n spinner.warn(chalk.yellow('No target locales to translate. Add more locales to your config.'));\n return;\n }\n\n // Load source locale data\n const sourceLocale = config.defaultLocale;\n const sourceData = storage.loadLocale(sourceLocale);\n\n if (!sourceData) {\n spinner.fail(chalk.red(`Source locale ${sourceLocale} not found. Run 'lokal scan' first.`));\n process.exit(1);\n }\n\n // Translate to each target locale\n for (const targetLocale of targetLocales) {\n const translateSpinner = ora(`Translating to ${chalk.cyan(targetLocale)}...`).start();\n\n // Load existing target data (if any)\n const targetLocaleFile = storage.loadLocale(targetLocale);\n const targetData: LocaleData = targetLocaleFile ? targetLocaleFile.data : {};\n\n // Translate missing keys\n const translatedData = await translator.translateMissingKeys(\n sourceData.data,\n targetData,\n sourceLocale,\n targetLocale\n );\n\n // Save translated data\n storage.saveLocale(targetLocale, translatedData);\n\n translateSpinner.succeed(chalk.green(`Translated to ${chalk.bold(targetLocale)}`));\n\n if (options.verbose) {\n // Show sample translations\n const keys = Object.keys(translatedData).slice(0, 5);\n for (const key of keys) {\n const value = translatedData[key];\n if (typeof value === 'string') {\n console.log(chalk.gray(` ${key}: ${value}`));\n }\n }\n }\n }\n\n console.log(chalk.bold('\\n✓ Translation complete!'));\n console.log(chalk.gray(`\\nRun `) + chalk.cyan('npx lokal scan') + chalk.gray(' to see updated translations'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Translation failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerTranslateCommand(program: Command): void {\n program\n .command('translate')\n .description('Translate missing strings using AI')\n .option('-c, --config <path>', 'Path to config file')\n .option('-l, --locale <locale>', 'Specific locale to translate')\n .option('-a, --all', 'Translate all locales', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(translateCommand);\n}\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTWrapper, ConfigLoader, FileStorage, type WrappedString, type WrapResult } from 'lokal-core';\n\n// Type for wrapDirectory result\ninterface WrapDirectoryResult {\n results: WrapResult[];\n modifiedFiles: number;\n errors: string[];\n skipped: string[];\n}\n\ninterface WrapOptions {\n config?: string;\n src?: string;\n function?: string;\n dryRun?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Auto-wrap translatable strings in source files\n * Converts plain text to t(\"key\") calls\n */\nexport async function wrapCommand(options: WrapOptions): Promise<void> {\n const spinner = ora('Preparing to wrap strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n\n // Determine source directory\n const sourceDir = options.src\n ? path.resolve(projectRoot, options.src)\n : path.resolve(projectRoot, config.sourceDir);\n\n // Check if source directory exists\n if (!fs.existsSync(sourceDir)) {\n spinner.fail(chalk.red(`Source directory not found: ${sourceDir}`));\n process.exit(1);\n }\n\n // Create wrapper\n const wrapper = new ASTWrapper({\n functionName: options.function || config.functionName || 't',\n componentName: config.componentName || 'T',\n });\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)} for translatable strings...`;\n\n // First pass: collect all wrapped strings without modifying\n const results = wrapper.wrapDirectory(sourceDir, ['.js', '.jsx', '.ts', '.tsx'], true) as WrapDirectoryResult;\n\n // Count total strings to wrap\n let totalStrings = 0;\n const fileResults: { file: string, wrapped: WrappedString[] }[] = [];\n\n for (const result of results.results) {\n if (result.wrapped.length > 0) {\n fileResults.push({\n file: result.file,\n wrapped: result.wrapped\n });\n totalStrings += result.wrapped.length;\n }\n }\n\n // Show skipped files (already wrapped)\n if (results.skipped && results.skipped.length > 0) {\n console.log(chalk.bold('\\n⚠ Skipped (already wrapped):'));\n for (const file of results.skipped.slice(0, 5)) {\n console.log(chalk.gray(` ${path.relative(projectRoot, file)}`));\n }\n if (results.skipped.length > 5) {\n console.log(chalk.gray(` ... and ${results.skipped.length - 5} more`));\n }\n }\n\n // Show errors\n if (results.errors && results.errors.length > 0) {\n console.log(chalk.bold('\\n⚠ Errors:'));\n for (const error of results.errors.slice(0, 5)) {\n console.log(chalk.red(` ${error}`));\n }\n if (results.errors.length > 5) {\n console.log(chalk.red(` ... and ${results.errors.length - 5} more`));\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(totalStrings)} strings to wrap in ${chalk.bold(fileResults.length)} files`));\n\n if (totalStrings === 0) {\n spinner.info(chalk.gray('No strings found that need wrapping.'));\n return;\n }\n\n // Show preview\n if (!options.dryRun) {\n console.log(chalk.bold('\\nPreview (first 10 files):'));\n let count = 0;\n for (const fileResult of fileResults.slice(0, 10)) {\n console.log(chalk.cyan(`\\n${path.relative(projectRoot, fileResult.file)}:`));\n for (const wrapped of fileResult.wrapped.slice(0, 5)) {\n console.log(chalk.gray(` \"${wrapped.original}\" → ${wrapped.wrapped}`));\n count++;\n }\n if (fileResult.wrapped.length > 5) {\n console.log(chalk.gray(` ... and ${fileResult.wrapped.length - 5} more`));\n }\n }\n if (fileResults.length > 10) {\n console.log(chalk.gray(`\\n... and ${fileResults.length - 10} more files`));\n }\n\n console.log(chalk.bold('\\n⚠ This will modify your source files!'));\n console.log(chalk.gray('Use --dry-run to preview without making changes'));\n } else {\n // Dry run - show what would be changed\n console.log(chalk.bold('\\nDry Run - Files that would be modified:'));\n for (const fileResult of fileResults) {\n console.log(chalk.cyan(` ${path.relative(projectRoot, fileResult.file)}`) +\n chalk.gray(` (${fileResult.wrapped.length} strings)`));\n }\n }\n\n if (options.dryRun) {\n spinner.info(chalk.yellow('Dry run complete. No files were modified.'));\n return;\n }\n\n // Confirm before making changes\n const confirmSpinner = ora('Applying changes...').start();\n\n // Apply changes to each file\n let modifiedCount = 0;\n for (const fileResult of fileResults) {\n const result = wrapper.wrapFile(fileResult.file);\n if (result.modified) {\n modifiedCount++;\n }\n }\n\n confirmSpinner.succeed(chalk.green(`Modified ${chalk.bold(modifiedCount)} files`));\n\n // Also update the locale file with the new keys\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n\n // Collect all new keys\n const newKeys: Record<string, string> = {};\n for (const fileResult of fileResults) {\n for (const wrapped of fileResult.wrapped) {\n newKeys[wrapped.key] = wrapped.original;\n }\n }\n\n // Add keys to default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n let existingData: Record<string, any> = {};\n\n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Merge new keys\n const mergedData = storage.mergeLocaleData(defaultLocale, newKeys);\n storage.saveLocale(defaultLocale, mergedData);\n\n console.log(chalk.green(`\\n✓ Added ${chalk.bold(Object.keys(newKeys).length)} new keys to locales/${defaultLocale}.json`));\n\n // Show next steps\n console.log(chalk.bold('\\nNext steps:'));\n console.log(chalk.gray(' 1. Review the changes in your source files'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate to other locales'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Wrap failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerWrapCommand(program: Command): void {\n program\n .command('wrap')\n .description('Automatically wrap translatable strings in source files')\n .option('-c, --config <path>', 'Path to config file')\n .option('-s, --src <path>', 'Source directory to scan')\n .option('-f, --function <name>', 'Translation function name', 't')\n .option('-d, --dry-run', 'Preview changes without modifying files', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(wrapCommand);\n}\n"],"mappings":"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","names":["import_chalk","ora","chalk","program","path","import_chalk","import_ora","ora","chalk","program","path","import_chalk","import_ora","import_lokal_core","ora","chalk","program","path","fs","import_chalk","import_ora","import_lokal_core","ora","chalk","program","chalk"]}
package/dist/index.mjs CHANGED
@@ -308,7 +308,25 @@ async function wrapCommand(options) {
308
308
  totalStrings += result.wrapped.length;
309
309
  }
310
310
  }
311
- spinner.succeed(chalk4.green(`Found ${chalk4.bold(totalStrings)} strings to wrap in ${chalk4.bold(results.modifiedFiles)} files`));
311
+ if (results.skipped && results.skipped.length > 0) {
312
+ console.log(chalk4.bold("\n\u26A0 Skipped (already wrapped):"));
313
+ for (const file of results.skipped.slice(0, 5)) {
314
+ console.log(chalk4.gray(` ${path4.relative(projectRoot, file)}`));
315
+ }
316
+ if (results.skipped.length > 5) {
317
+ console.log(chalk4.gray(` ... and ${results.skipped.length - 5} more`));
318
+ }
319
+ }
320
+ if (results.errors && results.errors.length > 0) {
321
+ console.log(chalk4.bold("\n\u26A0 Errors:"));
322
+ for (const error of results.errors.slice(0, 5)) {
323
+ console.log(chalk4.red(` ${error}`));
324
+ }
325
+ if (results.errors.length > 5) {
326
+ console.log(chalk4.red(` ... and ${results.errors.length - 5} more`));
327
+ }
328
+ }
329
+ spinner.succeed(chalk4.green(`Found ${chalk4.bold(totalStrings)} strings to wrap in ${chalk4.bold(fileResults.length)} files`));
312
330
  if (totalStrings === 0) {
313
331
  spinner.info(chalk4.gray("No strings found that need wrapping."));
314
332
  return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/commands/scan.ts","../src/commands/translate.ts","../src/commands/wrap.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { registerInitCommand } from './commands/init';\nimport { registerScanCommand } from './commands/scan';\nimport { registerTranslateCommand } from './commands/translate';\nimport { registerWrapCommand } from './commands/wrap';\n\nconst program = new Command();\n\nprogram\n .name('lokal')\n .description('AI-powered localization ecosystem for React and React Native')\n .version('1.0.0');\n\n// Register commands\nregisterInitCommand(program);\nregisterScanCommand(program);\nregisterTranslateCommand(program);\nregisterWrapCommand(program);\n\n// Global options\nprogram\n .option('-v, --verbose', 'Verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n process.env.LOKAL_VERBOSE = 'true';\n }\n });\n\n// Handle unknown commands\nprogram.on('command:*', () => {\n console.error(chalk.red(`Invalid command: ${program.args.join(' ')}`));\n console.log(chalk.gray(`See ${chalk.cyan('--help')} for a list of available commands.`));\n process.exit(1);\n});\n\n// Run the program\nprogram.parse(process.argv);\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\n\ninterface InitOptions {\n locales?: string;\n defaultLocale?: string;\n force?: boolean;\n}\n\n/**\n * Create the initial lokal config file and directory structure\n */\nexport async function initCommand(options: InitOptions): Promise<void> {\n const spinner = ora('Initializing LOKAL...').start();\n\n try {\n const projectRoot = process.cwd();\n const configPath = path.join(projectRoot, 'lokal.config.js');\n const localesDir = path.join(projectRoot, 'locales');\n\n // Parse locales\n const locales = options.locales\n ? options.locales.split(',').map(l => l.trim())\n : ['en'];\n\n const defaultLocale = options.defaultLocale || locales[0];\n\n // Check if already initialized\n if (fs.existsSync(configPath) && !options.force) {\n spinner.warn(chalk.yellow('LOKAL is already initialized. Use --force to reinitialize.'));\n return;\n }\n\n // Create config file\n const configContent = `module.exports = {\n // Supported locales\n locales: ${JSON.stringify(locales)},\n \n // Default locale\n defaultLocale: '${defaultLocale}',\n \n // Function name for translations (t(\"key\"))\n functionName: 't',\n \n // Component name for translations (<T>key</T>)\n componentName: 'T',\n \n // Source directory to scan\n sourceDir: './src',\n \n // Output directory for locale files\n outputDir: './locales',\n \n // AI Translation settings (optional)\n // ai: {\n // provider: 'openai', // or 'gemini'\n // apiKey: process.env.OPENAI_API_KEY,\n // model: 'gpt-4'\n // }\n};\n`;\n\n fs.writeFileSync(configPath, configContent, 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold('lokal.config.js')}`));\n\n // Create locales directory with default locale\n if (!fs.existsSync(localesDir)) {\n fs.mkdirSync(localesDir, { recursive: true });\n }\n\n // Create default locale file\n const defaultLocalePath = path.join(localesDir, `${defaultLocale}.json`);\n if (!fs.existsSync(defaultLocalePath)) {\n const initialData = {\n _meta: {\n generated: new Date().toISOString(),\n description: 'Default locale file'\n }\n };\n fs.writeFileSync(defaultLocalePath, JSON.stringify(initialData, null, 2), 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n }\n\n // Create .gitignore entry for locale files if .gitignore exists\n const gitignorePath = path.join(projectRoot, '.gitignore');\n if (fs.existsSync(gitignorePath)) {\n const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');\n if (!gitignoreContent.includes('/locales/')) {\n fs.appendFileSync(gitignorePath, '\\n# LOKAL translations\\nlocales/\\n');\n spinner.succeed(chalk.green('Updated .gitignore'));\n }\n }\n\n console.log(chalk.bold('\\n✓ LOKAL initialized successfully!'));\n console.log(chalk.gray('\\nNext steps:'));\n console.log(chalk.gray(' 1. Add translation strings to your code using t(\"key\") or <T>key</T>'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal scan') + chalk.gray(' to extract strings'));\n console.log(chalk.gray(' 3. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate with AI'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Failed to initialize: ${error}`));\n process.exit(1);\n }\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('init')\n .description('Initialize LOKAL in your project')\n .option('-l, --locales <locales>', 'Comma-separated list of locales', 'en')\n .option('-d, --default-locale <locale>', 'Default locale', 'en')\n .option('-f, --force', 'Force reinitialization', false)\n .action(initCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTParser, ConfigLoader, FileStorage, type ExtractedString } from 'lokal-core';\n\ninterface ScanOptions {\n config?: string;\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Scan source files for translation strings and update locale files\n */\nexport async function scanCommand(options: ScanOptions): Promise<void> {\n const spinner = ora('Scanning for translation strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n const sourceDir = path.resolve(projectRoot, config.sourceDir);\n const outputDir = options.output\n ? path.resolve(projectRoot, options.output)\n : path.resolve(projectRoot, config.outputDir);\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)}...`;\n\n // Create parser\n const parser = new ASTParser({\n filePath: sourceDir,\n functionName: config.functionName,\n componentName: config.componentName,\n });\n\n // Scan directory\n const result = parser.scanDirectory(sourceDir);\n\n if (result.errors.length > 0 && options.verbose) {\n for (const error of result.errors) {\n spinner.warn(chalk.yellow(error));\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(result.strings.length)} translation strings`));\n\n if (result.strings.length === 0) {\n spinner.info(chalk.gray('No strings found. Make sure to use t(\"key\") or <T>key</T> in your code.'));\n return;\n }\n\n // Create storage\n const storage = new FileStorage(outputDir);\n\n // Create unique key-value map\n const uniqueStrings = new Map<string, ExtractedString>();\n for (const str of result.strings) {\n uniqueStrings.set(str.key, str);\n }\n\n // Get the default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n\n // Merge with existing keys\n let existingData: Record<string, any> = {};\n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Convert extracted strings to flat key-value object\n const newData: Record<string, string> = {};\n for (const [key, value] of uniqueStrings) {\n // Use the key itself as the translation value for now\n newData[key] = existingData[key] || value.value;\n }\n\n // Save the merged data\n const mergedData = storage.mergeLocaleData(defaultLocale, newData);\n storage.saveLocale(defaultLocale, mergedData);\n\n spinner.succeed(chalk.green(`Updated ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n\n // Show sample of extracted strings\n if (options.verbose) {\n console.log(chalk.bold('\\nExtracted strings:'));\n const sampleKeys = Array.from(uniqueStrings.keys()).slice(0, 10);\n for (const key of sampleKeys) {\n console.log(chalk.gray(` • ${key}`));\n }\n if (uniqueStrings.size > 10) {\n console.log(chalk.gray(` ... and ${uniqueStrings.size - 10} more`));\n }\n }\n\n // Check for other locales that need translation\n const locales = storage.getAvailableLocales();\n const otherLocales = locales.filter(l => l !== defaultLocale);\n\n if (otherLocales.length > 0) {\n console.log(chalk.gray(`\\nOther locales detected: ${otherLocales.join(', ')}`));\n console.log(chalk.gray('Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate missing strings'));\n }\n\n } catch (error) {\n spinner.fail(chalk.red(`Scan failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerScanCommand(program: Command): void {\n program\n .command('scan')\n .description('Scan source files for translation strings')\n .option('-c, --config <path>', 'Path to config file')\n .option('-o, --output <path>', 'Output directory for locale files')\n .option('-v, --verbose', 'Verbose output', false)\n .action(scanCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport {\n ConfigLoader,\n FileStorage,\n AITranslator,\n TranslationProviderFactory,\n type LocaleData\n} from 'lokal-core';\n\ninterface TranslateOptions {\n config?: string;\n locale?: string;\n all?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Translate missing strings using AI\n */\nexport async function translateCommand(options: TranslateOptions): Promise<void> {\n const spinner = ora('Loading configuration...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n // Check if AI is configured\n if (!config.ai) {\n spinner.fail(chalk.red('AI provider not configured. Add ai configuration to lokal.config.js'));\n console.log(chalk.gray('\\nExample configuration:'));\n console.log(chalk.gray(' ai: {'));\n console.log(chalk.gray(' provider: \"openai\",'));\n console.log(chalk.gray(' apiKey: process.env.OPENAI_API_KEY'));\n console.log(chalk.gray(' }'));\n process.exit(1);\n }\n\n const apiKey = config.ai.apiKey || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY;\n if (!apiKey) {\n spinner.fail(chalk.red('No API key found. Set ai.apiKey in config or environment variable.'));\n process.exit(1);\n }\n\n spinner.text = 'Initializing AI translator...';\n\n // Create provider\n const provider = TranslationProviderFactory.create(\n config.ai.provider,\n apiKey,\n config.ai.model\n );\n\n // Create translator\n const translator = new AITranslator(provider);\n\n const projectRoot = process.cwd();\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n\n spinner.succeed('AI translator ready');\n\n // Determine which locales to translate\n let targetLocales: string[] = [];\n const availableLocales = config.locales || [];\n\n if (options.all) {\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale);\n } else if (options.locale) {\n targetLocales = [options.locale];\n } else {\n // Default: translate to first non-default locale\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale).slice(0, 1);\n }\n\n if (targetLocales.length === 0) {\n spinner.warn(chalk.yellow('No target locales to translate. Add more locales to your config.'));\n return;\n }\n\n // Load source locale data\n const sourceLocale = config.defaultLocale;\n const sourceData = storage.loadLocale(sourceLocale);\n\n if (!sourceData) {\n spinner.fail(chalk.red(`Source locale ${sourceLocale} not found. Run 'lokal scan' first.`));\n process.exit(1);\n }\n\n // Translate to each target locale\n for (const targetLocale of targetLocales) {\n const translateSpinner = ora(`Translating to ${chalk.cyan(targetLocale)}...`).start();\n\n // Load existing target data (if any)\n const targetLocaleFile = storage.loadLocale(targetLocale);\n const targetData: LocaleData = targetLocaleFile ? targetLocaleFile.data : {};\n\n // Translate missing keys\n const translatedData = await translator.translateMissingKeys(\n sourceData.data,\n targetData,\n sourceLocale,\n targetLocale\n );\n\n // Save translated data\n storage.saveLocale(targetLocale, translatedData);\n\n translateSpinner.succeed(chalk.green(`Translated to ${chalk.bold(targetLocale)}`));\n\n if (options.verbose) {\n // Show sample translations\n const keys = Object.keys(translatedData).slice(0, 5);\n for (const key of keys) {\n const value = translatedData[key];\n if (typeof value === 'string') {\n console.log(chalk.gray(` ${key}: ${value}`));\n }\n }\n }\n }\n\n console.log(chalk.bold('\\n✓ Translation complete!'));\n console.log(chalk.gray(`\\nRun `) + chalk.cyan('npx lokal scan') + chalk.gray(' to see updated translations'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Translation failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerTranslateCommand(program: Command): void {\n program\n .command('translate')\n .description('Translate missing strings using AI')\n .option('-c, --config <path>', 'Path to config file')\n .option('-l, --locale <locale>', 'Specific locale to translate')\n .option('-a, --all', 'Translate all locales', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(translateCommand);\n}\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTWrapper, ConfigLoader, FileStorage, type WrappedString } from 'lokal-core';\n\ninterface WrapOptions {\n config?: string;\n src?: string;\n function?: string;\n dryRun?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Auto-wrap translatable strings in source files\n * Converts plain text to t(\"key\") calls\n */\nexport async function wrapCommand(options: WrapOptions): Promise<void> {\n const spinner = ora('Preparing to wrap strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n \n // Determine source directory\n const sourceDir = options.src\n ? path.resolve(projectRoot, options.src)\n : path.resolve(projectRoot, config.sourceDir);\n\n // Check if source directory exists\n if (!fs.existsSync(sourceDir)) {\n spinner.fail(chalk.red(`Source directory not found: ${sourceDir}`));\n process.exit(1);\n }\n\n // Create wrapper\n const wrapper = new ASTWrapper({\n functionName: options.function || config.functionName || 't',\n componentName: config.componentName || 'T',\n });\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)} for translatable strings...`;\n\n // First pass: collect all wrapped strings without modifying\n const results = wrapper.wrapDirectory(sourceDir, ['.js', '.jsx', '.ts', '.tsx'], true);\n \n // Count total strings to wrap\n let totalStrings = 0;\n const fileResults: { file: string, wrapped: WrappedString[] }[] = [];\n \n for (const result of results.results) {\n if (result.wrapped.length > 0) {\n fileResults.push({\n file: result.file,\n wrapped: result.wrapped\n });\n totalStrings += result.wrapped.length;\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(totalStrings)} strings to wrap in ${chalk.bold(results.modifiedFiles)} files`));\n\n if (totalStrings === 0) {\n spinner.info(chalk.gray('No strings found that need wrapping.'));\n return;\n }\n\n // Show preview\n if (!options.dryRun) {\n console.log(chalk.bold('\\nPreview (first 10 files):'));\n let count = 0;\n for (const fileResult of fileResults.slice(0, 10)) {\n console.log(chalk.cyan(`\\n${path.relative(projectRoot, fileResult.file)}:`));\n for (const wrapped of fileResult.wrapped.slice(0, 5)) {\n console.log(chalk.gray(` \"${wrapped.original}\" → ${wrapped.wrapped}`));\n count++;\n }\n if (fileResult.wrapped.length > 5) {\n console.log(chalk.gray(` ... and ${fileResult.wrapped.length - 5} more`));\n }\n }\n if (fileResults.length > 10) {\n console.log(chalk.gray(`\\n... and ${fileResults.length - 10} more files`));\n }\n \n console.log(chalk.bold('\\n⚠ This will modify your source files!'));\n console.log(chalk.gray('Use --dry-run to preview without making changes'));\n } else {\n // Dry run - show what would be changed\n console.log(chalk.bold('\\nDry Run - Files that would be modified:'));\n for (const fileResult of fileResults) {\n console.log(chalk.cyan(` ${path.relative(projectRoot, fileResult.file)}`) + \n chalk.gray(` (${fileResult.wrapped.length} strings)`));\n }\n }\n\n if (options.dryRun) {\n spinner.info(chalk.yellow('Dry run complete. No files were modified.'));\n return;\n }\n\n // Confirm before making changes\n const confirmSpinner = ora('Applying changes...').start();\n\n // Apply changes to each file\n let modifiedCount = 0;\n for (const fileResult of fileResults) {\n const result = wrapper.wrapFile(fileResult.file);\n if (result.modified) {\n modifiedCount++;\n }\n }\n\n confirmSpinner.succeed(chalk.green(`Modified ${chalk.bold(modifiedCount)} files`));\n\n // Also update the locale file with the new keys\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n \n // Collect all new keys\n const newKeys: Record<string, string> = {};\n for (const fileResult of fileResults) {\n for (const wrapped of fileResult.wrapped) {\n newKeys[wrapped.key] = wrapped.original;\n }\n }\n\n // Add keys to default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n let existingData: Record<string, any> = {};\n \n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Merge new keys\n const mergedData = storage.mergeLocaleData(defaultLocale, newKeys);\n storage.saveLocale(defaultLocale, mergedData);\n\n console.log(chalk.green(`\\n✓ Added ${chalk.bold(Object.keys(newKeys).length)} new keys to locales/${defaultLocale}.json`));\n\n // Show next steps\n console.log(chalk.bold('\\nNext steps:'));\n console.log(chalk.gray(' 1. Review the changes in your source files'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate to other locales'));\n \n } catch (error) {\n spinner.fail(chalk.red(`Wrap failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerWrapCommand(program: Command): void {\n program\n .command('wrap')\n .description('Automatically wrap translatable strings in source files')\n .option('-c, --config <path>', 'Path to config file')\n .option('-s, --src <path>', 'Source directory to scan')\n .option('-f, --function <name>', 'Translation function name', 't')\n .option('-d, --dry-run', 'Preview changes without modifying files', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(wrapCommand);\n}\n"],"mappings":"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","names":["chalk","program","path","chalk","ora","program","path","chalk","ora","ConfigLoader","FileStorage","program","path","fs","chalk","ora","ConfigLoader","FileStorage","program","chalk"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/commands/scan.ts","../src/commands/translate.ts","../src/commands/wrap.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { registerInitCommand } from './commands/init';\nimport { registerScanCommand } from './commands/scan';\nimport { registerTranslateCommand } from './commands/translate';\nimport { registerWrapCommand } from './commands/wrap';\n\nconst program = new Command();\n\nprogram\n .name('lokal')\n .description('AI-powered localization ecosystem for React and React Native')\n .version('1.0.0');\n\n// Register commands\nregisterInitCommand(program);\nregisterScanCommand(program);\nregisterTranslateCommand(program);\nregisterWrapCommand(program);\n\n// Global options\nprogram\n .option('-v, --verbose', 'Verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n process.env.LOKAL_VERBOSE = 'true';\n }\n });\n\n// Handle unknown commands\nprogram.on('command:*', () => {\n console.error(chalk.red(`Invalid command: ${program.args.join(' ')}`));\n console.log(chalk.gray(`See ${chalk.cyan('--help')} for a list of available commands.`));\n process.exit(1);\n});\n\n// Run the program\nprogram.parse(process.argv);\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\n\ninterface InitOptions {\n locales?: string;\n defaultLocale?: string;\n force?: boolean;\n}\n\n/**\n * Create the initial lokal config file and directory structure\n */\nexport async function initCommand(options: InitOptions): Promise<void> {\n const spinner = ora('Initializing LOKAL...').start();\n\n try {\n const projectRoot = process.cwd();\n const configPath = path.join(projectRoot, 'lokal.config.js');\n const localesDir = path.join(projectRoot, 'locales');\n\n // Parse locales\n const locales = options.locales\n ? options.locales.split(',').map(l => l.trim())\n : ['en'];\n\n const defaultLocale = options.defaultLocale || locales[0];\n\n // Check if already initialized\n if (fs.existsSync(configPath) && !options.force) {\n spinner.warn(chalk.yellow('LOKAL is already initialized. Use --force to reinitialize.'));\n return;\n }\n\n // Create config file\n const configContent = `module.exports = {\n // Supported locales\n locales: ${JSON.stringify(locales)},\n \n // Default locale\n defaultLocale: '${defaultLocale}',\n \n // Function name for translations (t(\"key\"))\n functionName: 't',\n \n // Component name for translations (<T>key</T>)\n componentName: 'T',\n \n // Source directory to scan\n sourceDir: './src',\n \n // Output directory for locale files\n outputDir: './locales',\n \n // AI Translation settings (optional)\n // ai: {\n // provider: 'openai', // or 'gemini'\n // apiKey: process.env.OPENAI_API_KEY,\n // model: 'gpt-4'\n // }\n};\n`;\n\n fs.writeFileSync(configPath, configContent, 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold('lokal.config.js')}`));\n\n // Create locales directory with default locale\n if (!fs.existsSync(localesDir)) {\n fs.mkdirSync(localesDir, { recursive: true });\n }\n\n // Create default locale file\n const defaultLocalePath = path.join(localesDir, `${defaultLocale}.json`);\n if (!fs.existsSync(defaultLocalePath)) {\n const initialData = {\n _meta: {\n generated: new Date().toISOString(),\n description: 'Default locale file'\n }\n };\n fs.writeFileSync(defaultLocalePath, JSON.stringify(initialData, null, 2), 'utf-8');\n spinner.succeed(chalk.green(`Created ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n }\n\n // Create .gitignore entry for locale files if .gitignore exists\n const gitignorePath = path.join(projectRoot, '.gitignore');\n if (fs.existsSync(gitignorePath)) {\n const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');\n if (!gitignoreContent.includes('/locales/')) {\n fs.appendFileSync(gitignorePath, '\\n# LOKAL translations\\nlocales/\\n');\n spinner.succeed(chalk.green('Updated .gitignore'));\n }\n }\n\n console.log(chalk.bold('\\n✓ LOKAL initialized successfully!'));\n console.log(chalk.gray('\\nNext steps:'));\n console.log(chalk.gray(' 1. Add translation strings to your code using t(\"key\") or <T>key</T>'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal scan') + chalk.gray(' to extract strings'));\n console.log(chalk.gray(' 3. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate with AI'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Failed to initialize: ${error}`));\n process.exit(1);\n }\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('init')\n .description('Initialize LOKAL in your project')\n .option('-l, --locales <locales>', 'Comma-separated list of locales', 'en')\n .option('-d, --default-locale <locale>', 'Default locale', 'en')\n .option('-f, --force', 'Force reinitialization', false)\n .action(initCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTParser, ConfigLoader, FileStorage, type ExtractedString } from 'lokal-core';\n\ninterface ScanOptions {\n config?: string;\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Scan source files for translation strings and update locale files\n */\nexport async function scanCommand(options: ScanOptions): Promise<void> {\n const spinner = ora('Scanning for translation strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n const sourceDir = path.resolve(projectRoot, config.sourceDir);\n const outputDir = options.output\n ? path.resolve(projectRoot, options.output)\n : path.resolve(projectRoot, config.outputDir);\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)}...`;\n\n // Create parser\n const parser = new ASTParser({\n filePath: sourceDir,\n functionName: config.functionName,\n componentName: config.componentName,\n });\n\n // Scan directory\n const result = parser.scanDirectory(sourceDir);\n\n if (result.errors.length > 0 && options.verbose) {\n for (const error of result.errors) {\n spinner.warn(chalk.yellow(error));\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(result.strings.length)} translation strings`));\n\n if (result.strings.length === 0) {\n spinner.info(chalk.gray('No strings found. Make sure to use t(\"key\") or <T>key</T> in your code.'));\n return;\n }\n\n // Create storage\n const storage = new FileStorage(outputDir);\n\n // Create unique key-value map\n const uniqueStrings = new Map<string, ExtractedString>();\n for (const str of result.strings) {\n uniqueStrings.set(str.key, str);\n }\n\n // Get the default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n\n // Merge with existing keys\n let existingData: Record<string, any> = {};\n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Convert extracted strings to flat key-value object\n const newData: Record<string, string> = {};\n for (const [key, value] of uniqueStrings) {\n // Use the key itself as the translation value for now\n newData[key] = existingData[key] || value.value;\n }\n\n // Save the merged data\n const mergedData = storage.mergeLocaleData(defaultLocale, newData);\n storage.saveLocale(defaultLocale, mergedData);\n\n spinner.succeed(chalk.green(`Updated ${chalk.bold(`locales/${defaultLocale}.json`)}`));\n\n // Show sample of extracted strings\n if (options.verbose) {\n console.log(chalk.bold('\\nExtracted strings:'));\n const sampleKeys = Array.from(uniqueStrings.keys()).slice(0, 10);\n for (const key of sampleKeys) {\n console.log(chalk.gray(` • ${key}`));\n }\n if (uniqueStrings.size > 10) {\n console.log(chalk.gray(` ... and ${uniqueStrings.size - 10} more`));\n }\n }\n\n // Check for other locales that need translation\n const locales = storage.getAvailableLocales();\n const otherLocales = locales.filter(l => l !== defaultLocale);\n\n if (otherLocales.length > 0) {\n console.log(chalk.gray(`\\nOther locales detected: ${otherLocales.join(', ')}`));\n console.log(chalk.gray('Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate missing strings'));\n }\n\n } catch (error) {\n spinner.fail(chalk.red(`Scan failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerScanCommand(program: Command): void {\n program\n .command('scan')\n .description('Scan source files for translation strings')\n .option('-c, --config <path>', 'Path to config file')\n .option('-o, --output <path>', 'Output directory for locale files')\n .option('-v, --verbose', 'Verbose output', false)\n .action(scanCommand);\n}\n","import * as path from 'path';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport {\n ConfigLoader,\n FileStorage,\n AITranslator,\n TranslationProviderFactory,\n type LocaleData\n} from 'lokal-core';\n\ninterface TranslateOptions {\n config?: string;\n locale?: string;\n all?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Translate missing strings using AI\n */\nexport async function translateCommand(options: TranslateOptions): Promise<void> {\n const spinner = ora('Loading configuration...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n // Check if AI is configured\n if (!config.ai) {\n spinner.fail(chalk.red('AI provider not configured. Add ai configuration to lokal.config.js'));\n console.log(chalk.gray('\\nExample configuration:'));\n console.log(chalk.gray(' ai: {'));\n console.log(chalk.gray(' provider: \"openai\",'));\n console.log(chalk.gray(' apiKey: process.env.OPENAI_API_KEY'));\n console.log(chalk.gray(' }'));\n process.exit(1);\n }\n\n const apiKey = config.ai.apiKey || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY;\n if (!apiKey) {\n spinner.fail(chalk.red('No API key found. Set ai.apiKey in config or environment variable.'));\n process.exit(1);\n }\n\n spinner.text = 'Initializing AI translator...';\n\n // Create provider\n const provider = TranslationProviderFactory.create(\n config.ai.provider,\n apiKey,\n config.ai.model\n );\n\n // Create translator\n const translator = new AITranslator(provider);\n\n const projectRoot = process.cwd();\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n\n spinner.succeed('AI translator ready');\n\n // Determine which locales to translate\n let targetLocales: string[] = [];\n const availableLocales = config.locales || [];\n\n if (options.all) {\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale);\n } else if (options.locale) {\n targetLocales = [options.locale];\n } else {\n // Default: translate to first non-default locale\n targetLocales = availableLocales.filter(l => l !== config.defaultLocale).slice(0, 1);\n }\n\n if (targetLocales.length === 0) {\n spinner.warn(chalk.yellow('No target locales to translate. Add more locales to your config.'));\n return;\n }\n\n // Load source locale data\n const sourceLocale = config.defaultLocale;\n const sourceData = storage.loadLocale(sourceLocale);\n\n if (!sourceData) {\n spinner.fail(chalk.red(`Source locale ${sourceLocale} not found. Run 'lokal scan' first.`));\n process.exit(1);\n }\n\n // Translate to each target locale\n for (const targetLocale of targetLocales) {\n const translateSpinner = ora(`Translating to ${chalk.cyan(targetLocale)}...`).start();\n\n // Load existing target data (if any)\n const targetLocaleFile = storage.loadLocale(targetLocale);\n const targetData: LocaleData = targetLocaleFile ? targetLocaleFile.data : {};\n\n // Translate missing keys\n const translatedData = await translator.translateMissingKeys(\n sourceData.data,\n targetData,\n sourceLocale,\n targetLocale\n );\n\n // Save translated data\n storage.saveLocale(targetLocale, translatedData);\n\n translateSpinner.succeed(chalk.green(`Translated to ${chalk.bold(targetLocale)}`));\n\n if (options.verbose) {\n // Show sample translations\n const keys = Object.keys(translatedData).slice(0, 5);\n for (const key of keys) {\n const value = translatedData[key];\n if (typeof value === 'string') {\n console.log(chalk.gray(` ${key}: ${value}`));\n }\n }\n }\n }\n\n console.log(chalk.bold('\\n✓ Translation complete!'));\n console.log(chalk.gray(`\\nRun `) + chalk.cyan('npx lokal scan') + chalk.gray(' to see updated translations'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Translation failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerTranslateCommand(program: Command): void {\n program\n .command('translate')\n .description('Translate missing strings using AI')\n .option('-c, --config <path>', 'Path to config file')\n .option('-l, --locale <locale>', 'Specific locale to translate')\n .option('-a, --all', 'Translate all locales', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(translateCommand);\n}\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { ASTWrapper, ConfigLoader, FileStorage, type WrappedString, type WrapResult } from 'lokal-core';\n\n// Type for wrapDirectory result\ninterface WrapDirectoryResult {\n results: WrapResult[];\n modifiedFiles: number;\n errors: string[];\n skipped: string[];\n}\n\ninterface WrapOptions {\n config?: string;\n src?: string;\n function?: string;\n dryRun?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Auto-wrap translatable strings in source files\n * Converts plain text to t(\"key\") calls\n */\nexport async function wrapCommand(options: WrapOptions): Promise<void> {\n const spinner = ora('Preparing to wrap strings...').start();\n\n try {\n // Load config\n const configLoader = new ConfigLoader();\n let config;\n\n if (options.config) {\n config = configLoader.loadSync(options.config);\n } else {\n config = await configLoader.load();\n }\n\n const projectRoot = process.cwd();\n\n // Determine source directory\n const sourceDir = options.src\n ? path.resolve(projectRoot, options.src)\n : path.resolve(projectRoot, config.sourceDir);\n\n // Check if source directory exists\n if (!fs.existsSync(sourceDir)) {\n spinner.fail(chalk.red(`Source directory not found: ${sourceDir}`));\n process.exit(1);\n }\n\n // Create wrapper\n const wrapper = new ASTWrapper({\n functionName: options.function || config.functionName || 't',\n componentName: config.componentName || 'T',\n });\n\n spinner.text = `Scanning ${chalk.cyan(sourceDir)} for translatable strings...`;\n\n // First pass: collect all wrapped strings without modifying\n const results = wrapper.wrapDirectory(sourceDir, ['.js', '.jsx', '.ts', '.tsx'], true) as WrapDirectoryResult;\n\n // Count total strings to wrap\n let totalStrings = 0;\n const fileResults: { file: string, wrapped: WrappedString[] }[] = [];\n\n for (const result of results.results) {\n if (result.wrapped.length > 0) {\n fileResults.push({\n file: result.file,\n wrapped: result.wrapped\n });\n totalStrings += result.wrapped.length;\n }\n }\n\n // Show skipped files (already wrapped)\n if (results.skipped && results.skipped.length > 0) {\n console.log(chalk.bold('\\n⚠ Skipped (already wrapped):'));\n for (const file of results.skipped.slice(0, 5)) {\n console.log(chalk.gray(` ${path.relative(projectRoot, file)}`));\n }\n if (results.skipped.length > 5) {\n console.log(chalk.gray(` ... and ${results.skipped.length - 5} more`));\n }\n }\n\n // Show errors\n if (results.errors && results.errors.length > 0) {\n console.log(chalk.bold('\\n⚠ Errors:'));\n for (const error of results.errors.slice(0, 5)) {\n console.log(chalk.red(` ${error}`));\n }\n if (results.errors.length > 5) {\n console.log(chalk.red(` ... and ${results.errors.length - 5} more`));\n }\n }\n\n spinner.succeed(chalk.green(`Found ${chalk.bold(totalStrings)} strings to wrap in ${chalk.bold(fileResults.length)} files`));\n\n if (totalStrings === 0) {\n spinner.info(chalk.gray('No strings found that need wrapping.'));\n return;\n }\n\n // Show preview\n if (!options.dryRun) {\n console.log(chalk.bold('\\nPreview (first 10 files):'));\n let count = 0;\n for (const fileResult of fileResults.slice(0, 10)) {\n console.log(chalk.cyan(`\\n${path.relative(projectRoot, fileResult.file)}:`));\n for (const wrapped of fileResult.wrapped.slice(0, 5)) {\n console.log(chalk.gray(` \"${wrapped.original}\" → ${wrapped.wrapped}`));\n count++;\n }\n if (fileResult.wrapped.length > 5) {\n console.log(chalk.gray(` ... and ${fileResult.wrapped.length - 5} more`));\n }\n }\n if (fileResults.length > 10) {\n console.log(chalk.gray(`\\n... and ${fileResults.length - 10} more files`));\n }\n\n console.log(chalk.bold('\\n⚠ This will modify your source files!'));\n console.log(chalk.gray('Use --dry-run to preview without making changes'));\n } else {\n // Dry run - show what would be changed\n console.log(chalk.bold('\\nDry Run - Files that would be modified:'));\n for (const fileResult of fileResults) {\n console.log(chalk.cyan(` ${path.relative(projectRoot, fileResult.file)}`) +\n chalk.gray(` (${fileResult.wrapped.length} strings)`));\n }\n }\n\n if (options.dryRun) {\n spinner.info(chalk.yellow('Dry run complete. No files were modified.'));\n return;\n }\n\n // Confirm before making changes\n const confirmSpinner = ora('Applying changes...').start();\n\n // Apply changes to each file\n let modifiedCount = 0;\n for (const fileResult of fileResults) {\n const result = wrapper.wrapFile(fileResult.file);\n if (result.modified) {\n modifiedCount++;\n }\n }\n\n confirmSpinner.succeed(chalk.green(`Modified ${chalk.bold(modifiedCount)} files`));\n\n // Also update the locale file with the new keys\n const outputDir = path.resolve(projectRoot, config.outputDir);\n const storage = new FileStorage(outputDir);\n\n // Collect all new keys\n const newKeys: Record<string, string> = {};\n for (const fileResult of fileResults) {\n for (const wrapped of fileResult.wrapped) {\n newKeys[wrapped.key] = wrapped.original;\n }\n }\n\n // Add keys to default locale\n const defaultLocale = config.defaultLocale;\n const existingLocale = storage.loadLocale(defaultLocale);\n let existingData: Record<string, any> = {};\n\n if (existingLocale) {\n existingData = existingLocale.data as Record<string, any>;\n }\n\n // Merge new keys\n const mergedData = storage.mergeLocaleData(defaultLocale, newKeys);\n storage.saveLocale(defaultLocale, mergedData);\n\n console.log(chalk.green(`\\n✓ Added ${chalk.bold(Object.keys(newKeys).length)} new keys to locales/${defaultLocale}.json`));\n\n // Show next steps\n console.log(chalk.bold('\\nNext steps:'));\n console.log(chalk.gray(' 1. Review the changes in your source files'));\n console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate to other locales'));\n\n } catch (error) {\n spinner.fail(chalk.red(`Wrap failed: ${error}`));\n if (options.verbose) {\n console.error(error);\n }\n process.exit(1);\n }\n}\n\nexport function registerWrapCommand(program: Command): void {\n program\n .command('wrap')\n .description('Automatically wrap translatable strings in source files')\n .option('-c, --config <path>', 'Path to config file')\n .option('-s, --src <path>', 'Source directory to scan')\n .option('-f, --function <name>', 'Translation function name', 't')\n .option('-d, --dry-run', 'Preview changes without modifying files', false)\n .option('-v, --verbose', 'Verbose output', false)\n .action(wrapCommand);\n}\n"],"mappings":"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","names":["chalk","program","path","chalk","ora","program","path","chalk","ora","ConfigLoader","FileStorage","program","path","fs","chalk","ora","ConfigLoader","FileStorage","program","chalk"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devcoda/lokal-cli",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "CLI tool for LOKAL - Automates string extraction and AI translations",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {
@@ -3,7 +3,15 @@ import * as fs from 'fs';
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
5
  import ora from 'ora';
6
- import { ASTWrapper, ConfigLoader, FileStorage, type WrappedString } from 'lokal-core';
6
+ import { ASTWrapper, ConfigLoader, FileStorage, type WrappedString, type WrapResult } from 'lokal-core';
7
+
8
+ // Type for wrapDirectory result
9
+ interface WrapDirectoryResult {
10
+ results: WrapResult[];
11
+ modifiedFiles: number;
12
+ errors: string[];
13
+ skipped: string[];
14
+ }
7
15
 
8
16
  interface WrapOptions {
9
17
  config?: string;
@@ -32,7 +40,7 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
32
40
  }
33
41
 
34
42
  const projectRoot = process.cwd();
35
-
43
+
36
44
  // Determine source directory
37
45
  const sourceDir = options.src
38
46
  ? path.resolve(projectRoot, options.src)
@@ -53,12 +61,12 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
53
61
  spinner.text = `Scanning ${chalk.cyan(sourceDir)} for translatable strings...`;
54
62
 
55
63
  // First pass: collect all wrapped strings without modifying
56
- const results = wrapper.wrapDirectory(sourceDir, ['.js', '.jsx', '.ts', '.tsx'], true);
57
-
64
+ const results = wrapper.wrapDirectory(sourceDir, ['.js', '.jsx', '.ts', '.tsx'], true) as WrapDirectoryResult;
65
+
58
66
  // Count total strings to wrap
59
67
  let totalStrings = 0;
60
68
  const fileResults: { file: string, wrapped: WrappedString[] }[] = [];
61
-
69
+
62
70
  for (const result of results.results) {
63
71
  if (result.wrapped.length > 0) {
64
72
  fileResults.push({
@@ -69,7 +77,29 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
69
77
  }
70
78
  }
71
79
 
72
- spinner.succeed(chalk.green(`Found ${chalk.bold(totalStrings)} strings to wrap in ${chalk.bold(results.modifiedFiles)} files`));
80
+ // Show skipped files (already wrapped)
81
+ if (results.skipped && results.skipped.length > 0) {
82
+ console.log(chalk.bold('\n⚠ Skipped (already wrapped):'));
83
+ for (const file of results.skipped.slice(0, 5)) {
84
+ console.log(chalk.gray(` ${path.relative(projectRoot, file)}`));
85
+ }
86
+ if (results.skipped.length > 5) {
87
+ console.log(chalk.gray(` ... and ${results.skipped.length - 5} more`));
88
+ }
89
+ }
90
+
91
+ // Show errors
92
+ if (results.errors && results.errors.length > 0) {
93
+ console.log(chalk.bold('\n⚠ Errors:'));
94
+ for (const error of results.errors.slice(0, 5)) {
95
+ console.log(chalk.red(` ${error}`));
96
+ }
97
+ if (results.errors.length > 5) {
98
+ console.log(chalk.red(` ... and ${results.errors.length - 5} more`));
99
+ }
100
+ }
101
+
102
+ spinner.succeed(chalk.green(`Found ${chalk.bold(totalStrings)} strings to wrap in ${chalk.bold(fileResults.length)} files`));
73
103
 
74
104
  if (totalStrings === 0) {
75
105
  spinner.info(chalk.gray('No strings found that need wrapping.'));
@@ -93,14 +123,14 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
93
123
  if (fileResults.length > 10) {
94
124
  console.log(chalk.gray(`\n... and ${fileResults.length - 10} more files`));
95
125
  }
96
-
126
+
97
127
  console.log(chalk.bold('\n⚠ This will modify your source files!'));
98
128
  console.log(chalk.gray('Use --dry-run to preview without making changes'));
99
129
  } else {
100
130
  // Dry run - show what would be changed
101
131
  console.log(chalk.bold('\nDry Run - Files that would be modified:'));
102
132
  for (const fileResult of fileResults) {
103
- console.log(chalk.cyan(` ${path.relative(projectRoot, fileResult.file)}`) +
133
+ console.log(chalk.cyan(` ${path.relative(projectRoot, fileResult.file)}`) +
104
134
  chalk.gray(` (${fileResult.wrapped.length} strings)`));
105
135
  }
106
136
  }
@@ -127,7 +157,7 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
127
157
  // Also update the locale file with the new keys
128
158
  const outputDir = path.resolve(projectRoot, config.outputDir);
129
159
  const storage = new FileStorage(outputDir);
130
-
160
+
131
161
  // Collect all new keys
132
162
  const newKeys: Record<string, string> = {};
133
163
  for (const fileResult of fileResults) {
@@ -140,7 +170,7 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
140
170
  const defaultLocale = config.defaultLocale;
141
171
  const existingLocale = storage.loadLocale(defaultLocale);
142
172
  let existingData: Record<string, any> = {};
143
-
173
+
144
174
  if (existingLocale) {
145
175
  existingData = existingLocale.data as Record<string, any>;
146
176
  }
@@ -155,7 +185,7 @@ export async function wrapCommand(options: WrapOptions): Promise<void> {
155
185
  console.log(chalk.bold('\nNext steps:'));
156
186
  console.log(chalk.gray(' 1. Review the changes in your source files'));
157
187
  console.log(chalk.gray(' 2. Run ') + chalk.cyan('npx lokal translate') + chalk.gray(' to translate to other locales'));
158
-
188
+
159
189
  } catch (error) {
160
190
  spinner.fail(chalk.red(`Wrap failed: ${error}`));
161
191
  if (options.verbose) {