gt 2.20.4 → 2.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/api/collectUserEditDiffs.d.ts +2 -0
  3. package/dist/api/collectUserEditDiffs.js +31 -8
  4. package/dist/api/collectUserEditDiffs.js.map +1 -1
  5. package/dist/api/downloadFileBatch.js +13 -6
  6. package/dist/api/downloadFileBatch.js.map +1 -1
  7. package/dist/cli/base.js +2 -2
  8. package/dist/cli/base.js.map +1 -1
  9. package/dist/cli/commands/upload.js +30 -11
  10. package/dist/cli/commands/upload.js.map +1 -1
  11. package/dist/console/index.d.ts +4 -0
  12. package/dist/console/index.js +2 -1
  13. package/dist/console/index.js.map +1 -1
  14. package/dist/formats/files/aggregateFiles.js +39 -2
  15. package/dist/formats/files/aggregateFiles.js.map +1 -1
  16. package/dist/formats/files/localeContent.d.ts +18 -0
  17. package/dist/formats/files/localeContent.js +34 -0
  18. package/dist/formats/files/localeContent.js.map +1 -0
  19. package/dist/formats/files/supportedFiles.d.ts +2 -1
  20. package/dist/formats/files/supportedFiles.js +4 -2
  21. package/dist/formats/files/supportedFiles.js.map +1 -1
  22. package/dist/formats/files/transformFormat.d.ts +2 -0
  23. package/dist/formats/files/transformFormat.js +6 -3
  24. package/dist/formats/files/transformFormat.js.map +1 -1
  25. package/dist/formats/xcstrings/mergeXcstrings.d.ts +13 -0
  26. package/dist/formats/xcstrings/mergeXcstrings.js +71 -0
  27. package/dist/formats/xcstrings/mergeXcstrings.js.map +1 -0
  28. package/dist/formats/xcstrings/parseXcstrings.d.ts +43 -0
  29. package/dist/formats/xcstrings/parseXcstrings.js +123 -0
  30. package/dist/formats/xcstrings/parseXcstrings.js.map +1 -0
  31. package/dist/fs/config/parseFilesConfig.d.ts +2 -2
  32. package/dist/fs/config/parseFilesConfig.js +17 -3
  33. package/dist/fs/config/parseFilesConfig.js.map +1 -1
  34. package/dist/generated/version.d.ts +1 -1
  35. package/dist/generated/version.js +1 -1
  36. package/dist/generated/version.js.map +1 -1
  37. package/dist/state/recentDownloads.d.ts +1 -1
  38. package/dist/state/recentDownloads.js +3 -1
  39. package/dist/state/recentDownloads.js.map +1 -1
  40. package/dist/utils/api.d.ts +1 -1
  41. package/dist/utils/api.js +2 -1
  42. package/dist/utils/api.js.map +1 -1
  43. package/dist/utils/persistPostprocessHashes.d.ts +1 -1
  44. package/dist/utils/persistPostprocessHashes.js +18 -14
  45. package/dist/utils/persistPostprocessHashes.js.map +1 -1
  46. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/cli/base.ts"],"sourcesContent":["import { Command } from 'commander';\nimport {\n DEFAULT_TRANSLATIONS_DIR,\n DEFAULT_VITE_TRANSLATIONS_DIR,\n} from '../utils/constants.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport {\n displayHeader,\n promptText,\n logErrorAndExit,\n exitSync,\n promptConfirm,\n promptMultiSelect,\n promptSelect,\n promptGlobPatterns,\n} from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { lottieTranslateError } from '../console/index.js';\nimport { parseGlobPatterns } from '../console/promptParsing.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {\n FilesOptions,\n Settings,\n SupportedLibraries,\n SetupOptions,\n TranslateFlags,\n SharedFlags,\n} from '../types/index.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport chalk from 'chalk';\nimport { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';\nimport { handleSetupReactCommand } from '../setup/wizard.js';\nimport {\n isPackageInstalled,\n searchForPackageJson,\n} from '../utils/packageJson.js';\nimport { getDesiredLocales } from '../setup/userInput.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { retrieveCredentials, setCredentials } from '../utils/credentials.js';\nimport { areCredentialsSet } from '../utils/credentials.js';\nimport { upload } from './commands/upload.js';\nimport { attachSharedFlags, attachTranslateFlags } from './flags.js';\nimport { handleStage } from './commands/stage.js';\nimport { handleSetupProject } from './commands/setupProject.js';\nimport { handleDownload } from './commands/download.js';\nimport {\n handleTranslate,\n postProcessTranslations,\n} from './commands/translate.js';\nimport {\n getNeedsPostprocessing,\n clearDownloaded,\n} from '../state/recentDownloads.js';\nimport { clearWarnings } from '../state/translateWarnings.js';\nimport { displayTranslateSummary } from '../console/displayTranslateSummary.js';\nimport updateConfig from '../fs/config/updateConfig.js';\nimport { loadConfig } from '../fs/config/loadConfig.js';\nimport { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';\nimport { saveLocalEdits } from '../api/saveLocalEdits.js';\nimport {\n hasValidApiKey,\n hasValidCredentials,\n} from './commands/utils/validation.js';\nimport processSharedStaticAssets, {\n mirrorAssetsToLocales,\n} from '../utils/sharedStaticAssets.js';\nimport { setupLocadex } from '../locadex/setupFlow.js';\nimport { detectFramework } from '../setup/detectFramework.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from '../setup/frameworkUtils.js';\nimport { INLINE_LIBRARIES, Libraries } from '../types/libraries.js';\nimport { handleEnqueue } from './commands/enqueue.js';\nimport { splitMintlifyLanguageRefs } from '../utils/splitMintlifyLanguageRefs.js';\nimport { runMergeDriver } from '../git/mergeDrivers.js';\nimport { setupGitMergeDrivers } from '../git/setupMergeDrivers.js';\nimport { warnReactPackageCompatibility } from '../utils/reactPackageCompatibility.js';\nimport {\n createDiagnosticMessage,\n formatDiagnosticErrorDetails,\n} from 'generaltranslation/internal';\nimport { setupViteSPA } from '../setup/setupViteSPA.js';\nimport { manifestDirectlyDeclaresGTVue } from '@generaltranslation/vue-extractor/integration';\nimport { api } from '../utils/api.js';\nimport { handleApiCommand, type ApiCommandOptions } from './commands/api.js';\n\nconst ID_COMPATIBILITY_WARNING_COMMANDS = new Set([\n 'download',\n 'enqueue',\n 'generate',\n 'setup',\n 'stage',\n 'translate',\n 'validate',\n]);\nconst workspaceRootSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The setup wizard cannot run from a monorepo workspace root',\n why: 'GT must be configured in the specific app you want to localize',\n fix: \"Change to that app's directory and rerun `npx gt@latest`\",\n});\nfunction createProjectCommandError(\n whatHappened: string,\n error: unknown\n): string {\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened,\n details: formatDiagnosticErrorDetails(error),\n });\n}\n\nconst electronSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened:\n 'The automatic setup wizard is not ready for Electron applications',\n docsUrl: 'https://generaltranslation.com/docs/react',\n});\n\nasync function exitIfUnsupportedSetupTarget(): Promise<void> {\n const packageJson = await searchForPackageJson();\n if (packageJson && isPackageInstalled('electron', packageJson, false, true)) {\n logErrorAndExit(electronSetupError);\n }\n if (\n fs.existsSync(path.join(process.cwd(), 'pnpm-workspace.yaml')) ||\n packageJson?.workspaces\n ) {\n logErrorAndExit(workspaceRootSetupError);\n }\n}\n\nexport type UploadOptions = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n defaultLocale?: string;\n};\n\nexport type LoginOptions = {\n config?: string;\n keyType?: 'development' | 'production' | 'all';\n};\n\nexport type GitSetupOptions = {\n config?: string;\n dryRun?: boolean;\n omitConfigIds?: boolean;\n driverCommand?: string;\n};\n\ntype LocalTranslationGuidanceOptions = {\n generatedLoader: boolean;\n runtimeSetup: InlineRuntimeSetup;\n translationsDir: string;\n};\n\ntype InlineRuntimeSetup = {\n hasOtherInlineRuntime: boolean;\n hasVueRuntime: boolean;\n ranReactSetup: boolean;\n};\n\nexport class BaseCLI {\n protected library: SupportedLibraries;\n protected additionalModules: SupportedLibraries[];\n protected program: Command;\n // Constructor is shared amongst all CLI class types\n public constructor(\n program: Command,\n library: SupportedLibraries,\n additionalModules?: SupportedLibraries[]\n ) {\n this.program = program;\n this.library = library;\n this.additionalModules = additionalModules || [];\n\n this.program.option(\n '--skip-version-check',\n 'Skip the monorepo GT package version consistency check'\n );\n this.program.option(\n '--suppress-id-compatibility-warning',\n 'Suppress the React package ID compatibility warning'\n );\n this.program.option(\n '-q, --quiet',\n 'Suppress informational output; only warnings and errors are shown'\n );\n // Apply --quiet before any other hook or command action runs so the\n // singleton logger is muted for the rest of the invocation. The flag is a\n // global root option, so commander resolves it in any position and for\n // nested commands (e.g. `gt git setup --quiet`).\n this.program.hook('preAction', () => {\n logger.setQuiet(Boolean(this.program.opts().quiet));\n });\n this.program.hook('preAction', async (thisCommand, actionCommand) => {\n // Nested commands (e.g. `gt git setup`) can share leaf names with\n // translation commands; only direct children of the root qualify\n if (actionCommand.parent !== thisCommand) return;\n if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;\n await warnReactPackageCompatibility(\n Boolean(this.program.opts().suppressIdCompatibilityWarning)\n );\n });\n\n this.setupInitCommand();\n this.setupConfigureCommand();\n this.setupUploadCommand();\n this.setupLoginCommand();\n this.setupSendDiffsCommand();\n this.setupApiCommand();\n this.setupProjectCommands();\n this.setupGitCommand();\n }\n // Init is never called in a child class\n public init() {\n this.setupSetupProjectCommand();\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n // Execute is called by the main program\n public execute() {\n // If no command is specified, run 'init'\n if (process.argv.length <= 2) {\n process.argv.push('init');\n }\n }\n\n protected setupSetupProjectCommand(): void {\n attachTranslateFlags(\n this.program\n .command('setup')\n .description(\n 'Upload source files and setup the project for translation'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Uploading source files and setting up project...');\n await this.handleSetupProject(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupStageCommand(): void {\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupEnqueueCommand(): void {\n attachTranslateFlags(\n this.program\n .command('enqueue')\n .description('Enqueues translations for a given set of files')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Enqueuing translations...');\n await this.handleEnqueue(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupDownloadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('download')\n .description('Download translations that were originally staged')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Downloading translations...');\n await this.handleDownload(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachTranslateFlags(\n this.program\n .command('translate')\n .description('Translate your project using General Translation')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Starting translation...');\n await this.handleTranslate(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupSendDiffsCommand(): void {\n attachSharedFlags(\n this.program\n .command('save-local')\n .description(\n 'Save local edits for all configured files by sending diffs (no translation enqueued)'\n )\n )\n .option('--publish', 'Publish translations to the CDN', false)\n .action(async (initOptions: SharedFlags) => {\n displayHeader('Saving local edits...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n if (!hasValidCredentials(settings)) return exitSync(1);\n await saveLocalEdits(settings);\n logger.endCommand('Saved local edits');\n });\n }\n\n protected setupApiCommand(): void {\n attachSharedFlags(\n this.program\n .command('api [endpoint]')\n .description('Make an authenticated request to the GT API')\n .option('-X, --method <method>', 'HTTP method', 'GET')\n .option('--input <file>', 'Request body file, or - for standard input')\n .option(\n '-H, --header <header>',\n 'Request header in \"Key: Value\" format',\n (header, headers: string[] | undefined) => [\n ...(headers ?? []),\n header,\n ]\n )\n .option('-i, --include', 'Include response status and headers')\n .option('--spec', 'Print the bundled OpenAPI specification')\n ).action((endpoint, options: ApiCommandOptions) =>\n handleApiCommand(endpoint, options)\n );\n }\n\n protected setupProjectCommands(): void {\n const projectCommand = this.program\n .command('project')\n .description('Manage General Translation projects');\n\n attachSharedFlags(\n projectCommand\n .command('create')\n .description(\n 'Create a General Translation project using an organization API key'\n )\n .requiredOption('--name <name>', 'Project name')\n .requiredOption('--default-locale <locale>', 'Project default locale')\n .option('--cdn-enabled', 'Enable CDN delivery', false)\n ).action(async (options) => {\n try {\n const settings = await generateSettings(options);\n // Project creation uses an organization key before a project ID exists.\n if (!hasValidApiKey(settings)) return exitSync(1);\n const { project } = await api.createProject({\n name: options.name,\n defaultLocale: options.defaultLocale,\n cdnEnabled: options.cdnEnabled,\n });\n logger.info(`Created ${project.name} (${project.id})`);\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError('Failed to create the project', error)\n );\n }\n });\n\n attachSharedFlags(\n projectCommand\n .command('status')\n .description('Check the status of a project setup job')\n .argument('<job-id>', 'Setup job ID')\n ).action(async (jobId, options) => {\n try {\n const settings = await generateSettings(options);\n if (!hasValidCredentials(settings)) return exitSync(1);\n const [status] = await api.checkJobStatus([jobId]);\n logger.info(status?.status ?? 'unknown');\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError(\n 'Failed to check the project setup status',\n error\n )\n );\n }\n });\n }\n\n protected setupGitCommand(): void {\n const gitCommand = this.program\n .command('git')\n .description('Configure Git integrations for General Translation');\n\n gitCommand\n .command('setup')\n .description('Set up GT merge drivers for generated translation files')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option('--dry-run', 'Print changes without writing files', false)\n .option(\n '--omit-config-ids',\n 'Persist omitConfigIds and remove generated config IDs'\n )\n .option(\n '--driver-command <command>',\n 'Command Git should use to invoke gt, e.g. \"pnpm exec gt\"'\n )\n .action(async (options: GitSetupOptions) => {\n displayHeader('Setting up GT Git merge drivers...');\n const settings = await generateSettings(options, undefined, {\n requireConfig: true,\n });\n const omitConfigIds = await this.resolveGitSetupOmitConfigIds(\n options,\n settings\n );\n const result = await setupGitMergeDrivers(settings, {\n dryRun: options.dryRun,\n omitConfigIds,\n driverCommand: options.driverCommand,\n });\n\n for (const line of result.addedAttributes) {\n logger.step(\n `${options.dryRun ? 'Would add' : 'Added'} ${chalk.cyan(\n line\n )} to ${chalk.cyan(result.gitattributesPath)}`\n );\n }\n if (result.addedAttributes.length === 0) {\n logger.info(`${chalk.cyan('.gitattributes')} is already configured.`);\n }\n\n for (const args of result.gitConfigCommands) {\n logger.step(\n `${options.dryRun ? 'Would run' : 'Configured'} ${chalk.cyan(\n `git config --local ${args.join(' ')}`\n )}`\n );\n }\n\n if (result.updatedConfig) {\n logger.step(\n `${options.dryRun ? 'Would persist' : 'Persisted'} ${chalk.cyan(\n 'omitConfigIds: true'\n )} in ${chalk.cyan(settings.config)}`\n );\n } else if (options.dryRun && !settings.omitConfigIds) {\n logger.info(\n `Run without ${chalk.cyan('--dry-run')} to be prompted to persist ${chalk.cyan(\n 'omitConfigIds: true'\n )}, or pass ${chalk.cyan('--omit-config-ids')}.`\n );\n }\n\n for (const warning of result.warnings) {\n logger.warn(chalk.yellow(warning));\n }\n\n logger.endCommand(\n options.dryRun\n ? 'Dry run complete.'\n : 'GT Git merge drivers configured.'\n );\n });\n\n gitCommand\n .command('merge-driver', { hidden: true })\n .argument('<driver>', 'Merge driver name')\n .argument('<base>', 'Common ancestor file')\n .argument('<ours>', 'Current branch file')\n .argument('<theirs>', 'Incoming branch file')\n .argument('[path]', 'Merged path')\n .action((driver: string, base: string, ours: string, theirs: string) => {\n if (driver !== 'gt-lock' && driver !== 'gtjson') {\n logger.error(`Unknown GT merge driver: ${driver}`);\n exitSync(1);\n }\n const result = runMergeDriver(driver, base, ours, theirs);\n if (!result.ok) {\n logger.error(result.reason);\n exitSync(1);\n }\n });\n }\n\n protected async resolveGitSetupOmitConfigIds(\n options: GitSetupOptions,\n settings: Settings\n ): Promise<boolean> {\n if (options.omitConfigIds) return true;\n // Already opted in: persist again so stale config IDs still get removed\n if (settings.omitConfigIds) return true;\n if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {\n return false;\n }\n return promptConfirm({\n message:\n 'Also set omitConfigIds: true to reduce gt.config.json merge conflicts?',\n defaultValue: true,\n });\n }\n\n protected async handleSetupProject(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n await handleSetupProject(initOptions, settings, this.library);\n }\n\n protected async handleStage(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Update settings.stageTranslations to true\n settings.stageTranslations = true;\n await updateConfig(settings.config, {\n stageTranslations: true,\n });\n }\n await handleStage(initOptions, settings, this.library, true);\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleEnqueue(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleEnqueue(initOptions, settings, this.library);\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleDownload(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleDownload(initOptions, settings, this.library);\n }\n\n protected async handleTranslate(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Lottie translations finish asynchronously server-side (layout\n // refinement runs after the translation job completes), so the immediate\n // translate flow would try to download them before they're ready. Only\n // the stage + download flow supports them.\n if (settings.files?.resolvedPaths.lottie?.length) {\n return logErrorAndExit(lottieTranslateError);\n }\n const results = await handleStage(\n initOptions,\n settings,\n this.library,\n false\n );\n if (results) {\n await handleTranslate(\n initOptions,\n settings,\n results.fileVersionData,\n results.jobData,\n results.branchData,\n results.publishMap,\n results.inlineLibrary\n );\n }\n } else {\n await handleDownload(initOptions, settings, this.library);\n }\n // Only postprocess files downloaded in this run\n const include = getNeedsPostprocessing();\n if (include.size > 0) {\n await postProcessTranslations(settings, include);\n }\n // Split Mintlify language entries into $ref files to keep docs.json small\n await splitMintlifyLanguageRefs(settings);\n // Mirror assets after translations are downloaded and locale dirs are populated\n await mirrorAssetsToLocales(settings);\n clearDownloaded();\n displayTranslateSummary();\n clearWarnings();\n }\n\n protected setupUploadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('upload')\n .description(\n 'Upload source files and translations to the General Translation platform'\n )\n ).action(async (initOptions: UploadOptions) => {\n displayHeader('Starting upload...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const options = { ...initOptions, ...settings };\n\n await this.handleUploadCommand(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupLoginCommand(): void {\n this.program\n .command('auth')\n .description('Generate General Translation API keys and project ID')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option(\n '-t, --key-type <type>',\n 'Type of key to generate, production | development | all'\n )\n .action(async (options: LoginOptions) => {\n displayHeader('Authenticating with General Translation...');\n if (!options.keyType) {\n options.keyType = await promptSelect<\n 'development' | 'production' | 'all'\n >({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n } else {\n if (\n options.keyType !== 'development' &&\n options.keyType !== 'production' &&\n options.keyType !== 'all'\n ) {\n logErrorAndExit(\n 'Invalid key type, must be development, production, or all'\n );\n }\n }\n await this.handleLoginCommand(options);\n logger.endCommand(\n `Done! ${options.keyType} keys have been generated and saved to your .env.local file.`\n );\n });\n }\n\n protected setupInitCommand(): void {\n this.program\n .command('init')\n .description(\n 'Run the setup wizard to configure your project for General Translation'\n )\n .option(\n '--src <paths...>',\n \"Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'\"\n )\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .action(async (options: SetupOptions) => {\n await exitIfUnsupportedSetupTarget();\n const settings = await generateSettings(options);\n displayHeader('Running setup wizard...');\n\n const framework = await detectFramework();\n\n const useAgent = await (async () => {\n let useAgentMessage;\n if (framework.name === 'mintlify') {\n useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;\n }\n if (framework.name === 'next-app') {\n useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;\n }\n if (useAgentMessage) {\n return await promptConfirm({\n message: useAgentMessage,\n defaultValue: false,\n });\n }\n return false;\n })();\n\n if (useAgent) {\n await setupLocadex(settings);\n logger.endCommand(\n 'Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex'\n );\n } else {\n // Get framework display info for the defaults message\n const frameworkDisplayName =\n framework.type === 'react'\n ? getFrameworkDisplayName(framework)\n : null;\n const library =\n framework.type === 'react'\n ? getReactFrameworkLibrary(framework)\n : null;\n\n // Build defaults description based on detected framework\n const defaultTranslationsDir =\n framework.name === 'vite'\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n const defaultsDescription =\n framework.name === 'vite'\n ? `${library} & initializeGTSPA, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : framework.type === 'react'\n ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : `Files saved locally in ${defaultTranslationsDir}`;\n\n // Ask if user wants to use defaults\n const useDefaults = await promptConfirm({\n message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,\n defaultValue: true,\n });\n\n let ranReactSetup = false;\n\n // so that people can run init in non-js projects\n if (framework.type === 'react') {\n const wrap = useDefaults\n ? true\n : await promptConfirm({\n message:\n framework.name === 'vite'\n ? `Would you like to install ${library} and configure initializeGTSPA? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n : `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n\n if (wrap) {\n logger.info(\n `${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`\n );\n await handleSetupReactCommand(options, framework, useDefaults);\n logger.endCommand(\n `Done! Since this wizard is experimental, please review the changes and make modifications as needed.\n\\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n );\n ranReactSetup = true;\n }\n }\n\n if (ranReactSetup) {\n logger.startCommand('Setting up project config...');\n }\n // Configure gt.config.json\n await this.handleInitCommand(\n ranReactSetup,\n useDefaults,\n framework.name === 'vite'\n );\n\n logger.endCommand(\n 'Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs'\n );\n }\n });\n }\n\n protected setupConfigureCommand(): void {\n this.program\n .command('configure')\n .description(\n 'Configure your project for General Translation. This will create a gt.config.json file in your codebase.'\n )\n .action(() => this.handleConfigureCommand());\n }\n\n protected async handleConfigureCommand(\n options?: SetupOptions\n ): Promise<void> {\n await exitIfUnsupportedSetupTarget();\n displayHeader('Configuring project...');\n\n logger.info(\n 'Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.'\n );\n\n // Configure gt.config.json\n const framework = await detectFramework();\n await this.handleInitCommand(\n false,\n false,\n framework.name === 'vite',\n options\n );\n\n logger.endCommand(\n 'Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard'\n );\n }\n\n protected async handleUploadCommand(\n settings: Settings & UploadOptions\n ): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n // Process all file types at once with a single call\n await upload(settings);\n }\n\n /** Describes installed runtimes without changing historical package lookup. */\n protected getInlineRuntimeSetup(\n packageJson: Record<string, unknown>,\n ranReactSetup: boolean = false\n ): InlineRuntimeSetup {\n return {\n hasOtherInlineRuntime: INLINE_LIBRARIES.some(\n (lib) =>\n lib !== Libraries.GT_VUE && isPackageInstalled(lib, packageJson)\n ),\n hasVueRuntime: manifestDirectlyDeclaresGTVue(packageJson),\n ranReactSetup,\n };\n }\n\n /** Returns whether any inline runtime is installed for setup. */\n protected isInlineRuntimeInstalled(\n packageJson: Record<string, unknown>\n ): boolean {\n const { hasOtherInlineRuntime, hasVueRuntime } =\n this.getInlineRuntimeSetup(packageJson);\n return hasOtherInlineRuntime || hasVueRuntime;\n }\n\n /** Returns whether every installed runtime can consume CDN translations. */\n protected supportsCDNStorage(runtimeSetup: InlineRuntimeSetup): boolean {\n return !runtimeSetup.hasVueRuntime;\n }\n\n /** Returns whether setup should generate a local runtime loader. */\n protected shouldGenerateLocalTranslationLoader(\n isVite: boolean,\n runtimeSetup: InlineRuntimeSetup\n ): boolean {\n if (isVite) return false;\n if (!runtimeSetup.hasVueRuntime) return true;\n return runtimeSetup.hasOtherInlineRuntime || runtimeSetup.ranReactSetup;\n }\n\n /** Returns framework guidance after selecting local translation storage. */\n protected getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir,\n }: LocalTranslationGuidanceOptions): string | undefined {\n const guidance: string[] = [];\n if (generatedLoader) {\n guidance.push(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.\nMake sure to add this function to your app configuration.\nSee https://generaltranslation.com/en/docs/next/guides/local-tx`);\n }\n if (runtimeSetup.hasVueRuntime) {\n guidance.push(`GT will write local translation files to ${translationsDir}.\nConfigure createGT({ loadTranslations }) to load files from that directory.\nSee https://www.npmjs.com/package/gt-vue`);\n }\n return guidance.length > 0 ? guidance.join('\\n') : undefined;\n }\n\n // Wizard for configuring gt.config.json\n protected async handleInitCommand(\n ranReactSetup: boolean,\n useDefaults: boolean = false,\n isVite: boolean = false,\n options?: SetupOptions\n ): Promise<void> {\n const configFilepath =\n options?.config ||\n (!isVite && fs.existsSync('src/gt.config.json')\n ? 'src/gt.config.json'\n : 'gt.config.json');\n const existingConfig = loadConfig(configFilepath);\n const { defaultLocale, locales } = await getDesiredLocales(existingConfig);\n\n const packageJson = await searchForPackageJson();\n\n // Ask if using another i18n library\n const runtimeSetup: InlineRuntimeSetup = packageJson\n ? this.getInlineRuntimeSetup(packageJson, ranReactSetup)\n : {\n hasOtherInlineRuntime: false,\n hasVueRuntime: false,\n ranReactSetup,\n };\n const isUsingGT =\n runtimeSetup.ranReactSetup ||\n runtimeSetup.hasOtherInlineRuntime ||\n runtimeSetup.hasVueRuntime;\n\n // Ask where the translations are stored\n const usingCDN = await (async () => {\n if (!isUsingGT) return false;\n if (useDefaults) return false; // Default to local\n if (!this.supportsCDNStorage(runtimeSetup)) return false;\n const selectedValue = await promptSelect({\n message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,\n options: [\n { value: 'local', label: 'Save locally' },\n { value: 'cdn', label: 'Use CDN' },\n ],\n defaultValue: 'local',\n });\n return selectedValue === 'cdn';\n })();\n\n const defaultTranslationsDir = isVite\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n // Ask where the translations are stored\n const translationsDir =\n isUsingGT && !usingCDN\n ? useDefaults\n ? defaultTranslationsDir\n : await promptText({\n message:\n 'What is the path to the directory where you would like to store your translation files?',\n defaultValue: defaultTranslationsDir,\n })\n : null;\n\n // Determine final translations directory with fallback\n const finalTranslationsDir =\n translationsDir?.trim() || defaultTranslationsDir;\n\n if (isUsingGT && !usingCDN) {\n const generatedLoader = this.shouldGenerateLocalTranslationLoader(\n isVite,\n runtimeSetup\n );\n if (generatedLoader) {\n await createLoadTranslationsFile(\n process.cwd(),\n finalTranslationsDir,\n locales\n );\n }\n const guidance = this.getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir: finalTranslationsDir,\n });\n if (guidance) logger.message(guidance);\n }\n\n const message = !isUsingGT\n ? 'What is the format of your language resource files? Select as many as applicable.\\nAdditionally, you can translate any other files you have in your project.'\n : `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim(\n '(To continue without selecting press Enter)'\n )}`;\n const fileExtensions =\n useDefaults && isUsingGT\n ? [] // Skip for GT projects when using defaults\n : await promptMultiSelect({\n message,\n options: [\n { value: 'json', label: FILE_EXT_TO_EXT_LABEL.json },\n { value: 'md', label: FILE_EXT_TO_EXT_LABEL.md },\n { value: 'mdx', label: FILE_EXT_TO_EXT_LABEL.mdx },\n { value: 'ts', label: FILE_EXT_TO_EXT_LABEL.ts },\n { value: 'js', label: FILE_EXT_TO_EXT_LABEL.js },\n { value: 'yaml', label: FILE_EXT_TO_EXT_LABEL.yaml },\n // TWILIO_CONTENT_JSON not supported in CLI init as its too niche\n ],\n required: !isUsingGT,\n });\n\n const files: FilesOptions = {};\n for (const fileExtension of fileExtensions) {\n const label = FILE_EXT_TO_EXT_LABEL[fileExtension];\n const paths = await promptGlobPatterns({\n label,\n message: `${chalk.cyan(FILE_EXT_TO_EXT_LABEL[fileExtension])}: Enter a space-separated list of glob patterns matching the location of the ${FILE_EXT_TO_EXT_LABEL[fileExtension]} files you would like to translate.\\nMake sure to include [locale] in the patterns.\\nSee https://generaltranslation.com/docs/cli/reference/config#include for more information.`,\n defaultValue: `./**/[locale]/*.${fileExtension}`,\n });\n\n files[fileExtension] = {\n include: parseGlobPatterns(paths),\n };\n }\n\n // Add GT translations if using GT and storing locally\n if (isUsingGT && !usingCDN) {\n files.gt = {\n output: path.join(finalTranslationsDir, `[locale].json`),\n };\n }\n\n // Create gt.config.json\n await createOrUpdateConfig(configFilepath, {\n defaultLocale,\n locales,\n src: options?.src,\n files: Object.keys(files).length > 0 ? files : undefined,\n framework: isVite ? 'vite' : undefined,\n publish: isUsingGT && usingCDN,\n clearPublish: runtimeSetup.hasVueRuntime && !usingCDN,\n });\n\n logger.success(\n `Edit ${chalk.cyan(\n configFilepath\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n if (ranReactSetup && isVite) {\n await setupViteSPA({\n appDirectory: process.cwd(),\n configFilepath,\n defaultLocale,\n locales,\n translationsDir: usingCDN ? undefined : finalTranslationsDir,\n });\n }\n\n // Install gt if not installed\n const isCLIInstalled = packageJson\n ? isPackageInstalled('gt', packageJson, true, true)\n : true; // if no package.json, we can't install it\n\n if (!isCLIInstalled && !(isUsingGT && isVite)) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner();\n spinner.start(\n `Installing gt as a dev dependency with ${packageManager.name}...`\n );\n await installPackage('gt', packageManager, true);\n spinner.stop(chalk.green('Installed gt.'));\n }\n\n // Set credentials\n if ((!isVite || !isUsingGT || usingCDN) && !areCredentialsSet()) {\n const loginQuestion = useDefaults\n ? true\n : await promptConfirm({\n message:\n 'Would you like the wizard to automatically generate API keys and a project ID for you?',\n defaultValue: true,\n });\n if (loginQuestion) {\n const settings = await generateSettings({});\n const keyType = useDefaults\n ? 'all'\n : await promptSelect<'development' | 'production' | 'all'>({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, isVite ? 'vite' : settings.framework);\n }\n }\n }\n protected async handleLoginCommand(options: LoginOptions): Promise<void> {\n const settings = await generateSettings({ config: options.config });\n const keyType = options.keyType || 'all';\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0FA,MAAM,oCAAoC,IAAI,IAAI;CAChD;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AACF,MAAM,0BAA0B,wBAAwB;CACtD,QAAQ;CACR,UAAU;CACV,cAAc;CACd,KAAK;CACL,KAAK;CACN,CAAC;AACF,SAAS,0BACP,cACA,OACQ;AACR,QAAO,wBAAwB;EAC7B,QAAQ;EACR,UAAU;EACV;EACA,SAAS,6BAA6B,MAAM;EAC7C,CAAC;;AAGJ,MAAM,qBAAqB,wBAAwB;CACjD,QAAQ;CACR,UAAU;CACV,cACE;CACF,SAAS;CACV,CAAC;AAEF,eAAe,+BAA8C;CAC3D,MAAM,cAAc,MAAM,sBAAsB;AAChD,KAAI,eAAe,mBAAmB,YAAY,aAAa,OAAO,KAAK,CACzE,iBAAgB,mBAAmB;AAErC,KACE,GAAG,WAAW,KAAK,KAAK,QAAQ,KAAK,EAAE,sBAAsB,CAAC,IAC9D,aAAa,WAEb,iBAAgB,wBAAwB;;AAmC5C,IAAa,UAAb,MAAqB;CACnB;CACA;CACA;CAEA,YACE,SACA,SACA,mBACA;AACA,OAAK,UAAU;AACf,OAAK,UAAU;AACf,OAAK,oBAAoB,qBAAqB,EAAE;AAEhD,OAAK,QAAQ,OACX,wBACA,yDACD;AACD,OAAK,QAAQ,OACX,uCACA,sDACD;AACD,OAAK,QAAQ,OACX,eACA,oEACD;AAKD,OAAK,QAAQ,KAAK,mBAAmB;AACnC,UAAO,SAAS,QAAQ,KAAK,QAAQ,MAAM,CAAC,MAAM,CAAC;IACnD;AACF,OAAK,QAAQ,KAAK,aAAa,OAAO,aAAa,kBAAkB;AAGnE,OAAI,cAAc,WAAW,YAAa;AAC1C,OAAI,CAAC,kCAAkC,IAAI,cAAc,MAAM,CAAC,CAAE;AAClE,SAAM,8BACJ,QAAQ,KAAK,QAAQ,MAAM,CAAC,+BAA+B,CAC5D;IACD;AAEF,OAAK,kBAAkB;AACvB,OAAK,uBAAuB;AAC5B,OAAK,oBAAoB;AACzB,OAAK,mBAAmB;AACxB,OAAK,uBAAuB;AAC5B,OAAK,iBAAiB;AACtB,OAAK,sBAAsB;AAC3B,OAAK,iBAAiB;;CAGxB,OAAc;AACZ,OAAK,0BAA0B;AAC/B,OAAK,mBAAmB;AACxB,OAAK,uBAAuB;AAC5B,OAAK,sBAAsB;AAC3B,OAAK,qBAAqB;;CAG5B,UAAiB;AAEf,MAAI,QAAQ,KAAK,UAAU,EACzB,SAAQ,KAAK,KAAK,OAAO;;CAI7B,2BAA2C;AACzC,uBACE,KAAK,QACF,QAAQ,QAAQ,CAChB,YACC,4DACD,CACJ,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,mDAAmD;AACjE,SAAM,KAAK,mBAAmB,YAAY;AAC1C,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,oBAAoC;AAClC,uBACE,KAAK,QACF,QAAQ,QAAQ,CAChB,YACC,2IACD,CACJ,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBACE,4DACD;AACD,SAAM,KAAK,YAAY,YAAY;AACnC,UAAO,WAAW,QAAQ;IAC1B;;;;;;;CAQJ,sBAAsC;AACpC,uBACE,KAAK,QACF,QAAQ,UAAU,CAClB,YAAY,iDAAiD,CACjE,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,4BAA4B;AAC1C,SAAM,KAAK,cAAc,YAAY;AACrC,UAAO,WAAW,QAAQ;IAC1B;;;;;;;CAQJ,uBAAuC;AACrC,uBACE,KAAK,QACF,QAAQ,WAAW,CACnB,YAAY,oDAAoD,CACpE,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,8BAA8B;AAC5C,SAAM,KAAK,eAAe,YAAY;AACtC,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,wBAAwC;AACtC,uBACE,KAAK,QACF,QAAQ,YAAY,CACpB,YAAY,mDAAmD,CACnE,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,0BAA0B;AACxC,SAAM,KAAK,gBAAgB,YAAY;AACvC,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,wBAAwC;AACtC,oBACE,KAAK,QACF,QAAQ,aAAa,CACrB,YACC,uFACD,CACJ,CACE,OAAO,aAAa,mCAAmC,MAAM,CAC7D,OAAO,OAAO,gBAA6B;AAC1C,iBAAc,wBAAwB;GACtC,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AACF,OAAI,CAAC,oBAAoB,SAAS,CAAE,QAAO,SAAS,EAAE;AACtD,SAAM,eAAe,SAAS;AAC9B,UAAO,WAAW,oBAAoB;IACtC;;CAGN,kBAAkC;AAChC,oBACE,KAAK,QACF,QAAQ,iBAAiB,CACzB,YAAY,8CAA8C,CAC1D,OAAO,yBAAyB,eAAe,MAAM,CACrD,OAAO,kBAAkB,6CAA6C,CACtE,OACC,yBACA,4CACC,QAAQ,YAAkC,CACzC,GAAI,WAAW,EAAE,EACjB,OACD,CACF,CACA,OAAO,iBAAiB,sCAAsC,CAC9D,OAAO,UAAU,0CAA0C,CAC/D,CAAC,QAAQ,UAAU,YAClB,iBAAiB,UAAU,QAAQ,CACpC;;CAGH,uBAAuC;EACrC,MAAM,iBAAiB,KAAK,QACzB,QAAQ,UAAU,CAClB,YAAY,sCAAsC;AAErD,oBACE,eACG,QAAQ,SAAS,CACjB,YACC,qEACD,CACA,eAAe,iBAAiB,eAAe,CAC/C,eAAe,6BAA6B,yBAAyB,CACrE,OAAO,iBAAiB,uBAAuB,MAAM,CACzD,CAAC,OAAO,OAAO,YAAY;AAC1B,OAAI;AAGF,QAAI,CAAC,eAAe,MAFG,iBAAiB,QAAQ,CAEnB,CAAE,QAAO,SAAS,EAAE;IACjD,MAAM,EAAE,YAAY,MAAM,IAAI,cAAc;KAC1C,MAAM,QAAQ;KACd,eAAe,QAAQ;KACvB,YAAY,QAAQ;KACrB,CAAC;AACF,WAAO,KAAK,WAAW,QAAQ,KAAK,IAAI,QAAQ,GAAG,GAAG;YAC/C,OAAO;AACd,WAAO,gBACL,0BAA0B,gCAAgC,MAAM,CACjE;;IAEH;AAEF,oBACE,eACG,QAAQ,SAAS,CACjB,YAAY,0CAA0C,CACtD,SAAS,YAAY,eAAe,CACxC,CAAC,OAAO,OAAO,OAAO,YAAY;AACjC,OAAI;AAEF,QAAI,CAAC,oBAAoB,MADF,iBAAiB,QAAQ,CACd,CAAE,QAAO,SAAS,EAAE;IACtD,MAAM,CAAC,UAAU,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC;AAClD,WAAO,KAAK,QAAQ,UAAU,UAAU;YACjC,OAAO;AACd,WAAO,gBACL,0BACE,4CACA,MACD,CACF;;IAEH;;CAGJ,kBAAkC;EAChC,MAAM,aAAa,KAAK,QACrB,QAAQ,MAAM,CACd,YAAY,qDAAqD;AAEpE,aACG,QAAQ,QAAQ,CAChB,YAAY,0DAA0D,CACtE,OACC,uBACA,sDACA,aAAa,CAAC,iBAAiB,CAAC,CACjC,CACA,OAAO,aAAa,uCAAuC,MAAM,CACjE,OACC,qBACA,wDACD,CACA,OACC,8BACA,6DACD,CACA,OAAO,OAAO,YAA6B;AAC1C,iBAAc,qCAAqC;GACnD,MAAM,WAAW,MAAM,iBAAiB,SAAS,KAAA,GAAW,EAC1D,eAAe,MAChB,CAAC;GACF,MAAM,gBAAgB,MAAM,KAAK,6BAC/B,SACA,SACD;GACD,MAAM,SAAS,MAAM,qBAAqB,UAAU;IAClD,QAAQ,QAAQ;IAChB;IACA,eAAe,QAAQ;IACxB,CAAC;AAEF,QAAK,MAAM,QAAQ,OAAO,gBACxB,QAAO,KACL,GAAG,QAAQ,SAAS,cAAc,QAAQ,GAAG,MAAM,KACjD,KACD,CAAC,MAAM,MAAM,KAAK,OAAO,kBAAkB,GAC7C;AAEH,OAAI,OAAO,gBAAgB,WAAW,EACpC,QAAO,KAAK,GAAG,MAAM,KAAK,iBAAiB,CAAC,yBAAyB;AAGvE,QAAK,MAAM,QAAQ,OAAO,kBACxB,QAAO,KACL,GAAG,QAAQ,SAAS,cAAc,aAAa,GAAG,MAAM,KACtD,sBAAsB,KAAK,KAAK,IAAI,GACrC,GACF;AAGH,OAAI,OAAO,cACT,QAAO,KACL,GAAG,QAAQ,SAAS,kBAAkB,YAAY,GAAG,MAAM,KACzD,sBACD,CAAC,MAAM,MAAM,KAAK,SAAS,OAAO,GACpC;YACQ,QAAQ,UAAU,CAAC,SAAS,cACrC,QAAO,KACL,eAAe,MAAM,KAAK,YAAY,CAAC,6BAA6B,MAAM,KACxE,sBACD,CAAC,YAAY,MAAM,KAAK,oBAAoB,CAAC,GAC/C;AAGH,QAAK,MAAM,WAAW,OAAO,SAC3B,QAAO,KAAK,MAAM,OAAO,QAAQ,CAAC;AAGpC,UAAO,WACL,QAAQ,SACJ,sBACA,mCACL;IACD;AAEJ,aACG,QAAQ,gBAAgB,EAAE,QAAQ,MAAM,CAAC,CACzC,SAAS,YAAY,oBAAoB,CACzC,SAAS,UAAU,uBAAuB,CAC1C,SAAS,UAAU,sBAAsB,CACzC,SAAS,YAAY,uBAAuB,CAC5C,SAAS,UAAU,cAAc,CACjC,QAAQ,QAAgB,MAAc,MAAc,WAAmB;AACtE,OAAI,WAAW,aAAa,WAAW,UAAU;AAC/C,WAAO,MAAM,4BAA4B,SAAS;AAClD,aAAS,EAAE;;GAEb,MAAM,SAAS,eAAe,QAAQ,MAAM,MAAM,OAAO;AACzD,OAAI,CAAC,OAAO,IAAI;AACd,WAAO,MAAM,OAAO,OAAO;AAC3B,aAAS,EAAE;;IAEb;;CAGN,MAAgB,6BACd,SACA,UACkB;AAClB,MAAI,QAAQ,cAAe,QAAO;AAElC,MAAI,SAAS,cAAe,QAAO;AACnC,MAAI,QAAQ,UAAU,CAAC,QAAQ,MAAM,SAAS,CAAC,QAAQ,OAAO,MAC5D,QAAO;AAET,SAAO,cAAc;GACnB,SACE;GACF,cAAc;GACf,CAAC;;CAGJ,MAAgB,mBACd,aACe;EACf,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AAGF,QAAM,0BAA0B,SAAS;AAEzC,QAAM,mBAAmB,aAAa,UAAU,KAAK,QAAQ;;CAG/D,MAAgB,YAAY,aAA4C;EACtE,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AAGF,QAAM,0BAA0B,SAAS;AAEzC,MAAI,CAAC,SAAS,mBAAmB;AAE/B,YAAS,oBAAoB;AAC7B,SAAM,aAAa,SAAS,QAAQ,EAClC,mBAAmB,MACpB,CAAC;;AAEJ,QAAM,YAAY,aAAa,UAAU,KAAK,SAAS,KAAK;;;;;;;CAQ9D,MAAgB,cAAc,aAA4C;AAIxE,QAAM,cAAc,aAAa,MAHV,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC,EACyC,KAAK,QAAQ;;;;;;;CAQ1D,MAAgB,eAAe,aAA4C;AAIzE,QAAM,eAAe,aAAa,MAHX,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC,EAC0C,KAAK,QAAQ;;CAG3D,MAAgB,gBAAgB,aAA4C;EAC1E,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AAGF,QAAM,0BAA0B,SAAS;AAEzC,MAAI,CAAC,SAAS,mBAAmB;AAK/B,OAAI,SAAS,OAAO,cAAc,QAAQ,OACxC,QAAO,gBAAgB,qBAAqB;GAE9C,MAAM,UAAU,MAAM,YACpB,aACA,UACA,KAAK,SACL,MACD;AACD,OAAI,QACF,OAAM,gBACJ,aACA,UACA,QAAQ,iBACR,QAAQ,SACR,QAAQ,YACR,QAAQ,YACR,QAAQ,cACT;QAGH,OAAM,eAAe,aAAa,UAAU,KAAK,QAAQ;EAG3D,MAAM,UAAU,wBAAwB;AACxC,MAAI,QAAQ,OAAO,EACjB,OAAM,wBAAwB,UAAU,QAAQ;AAGlD,QAAM,0BAA0B,SAAS;AAEzC,QAAM,sBAAsB,SAAS;AACrC,mBAAiB;AACjB,2BAAyB;AACzB,iBAAe;;CAGjB,qBAAqC;AACnC,uBACE,KAAK,QACF,QAAQ,SAAS,CACjB,YACC,2EACD,CACJ,CAAC,OAAO,OAAO,gBAA+B;AAC7C,iBAAc,qBAAqB;GACnC,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;GAEF,MAAM,UAAU;IAAE,GAAG;IAAa,GAAG;IAAU;AAE/C,SAAM,KAAK,oBAAoB,QAAQ;AACvC,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,oBAAoC;AAClC,OAAK,QACF,QAAQ,OAAO,CACf,YAAY,uDAAuD,CACnE,OACC,uBACA,sDACA,aAAa,CAAC,iBAAiB,CAAC,CACjC,CACA,OACC,yBACA,0DACD,CACA,OAAO,OAAO,YAA0B;AACvC,iBAAc,6CAA6C;AAC3D,OAAI,CAAC,QAAQ,QACX,SAAQ,UAAU,MAAM,aAEtB;IACA,SAAS;IACT,SAAS;KACP;MAAE,OAAO;MAAe,OAAO;MAAe;KAC9C;MAAE,OAAO;MAAc,OAAO;MAAc;KAC5C;MAAE,OAAO;MAAO,OAAO;MAAQ;KAChC;IACD,cAAc;IACf,CAAC;YAGA,QAAQ,YAAY,iBACpB,QAAQ,YAAY,gBACpB,QAAQ,YAAY,MAEpB,iBACE,4DACD;AAGL,SAAM,KAAK,mBAAmB,QAAQ;AACtC,UAAO,WACL,SAAS,QAAQ,QAAQ,8DAC1B;IACD;;CAGN,mBAAmC;AACjC,OAAK,QACF,QAAQ,OAAO,CACf,YACC,yEACD,CACA,OACC,oBACA,0MACD,CACA,OACC,uBACA,sDACA,aAAa,CAAC,iBAAiB,CAAC,CACjC,CACA,OAAO,OAAO,YAA0B;AACvC,SAAM,8BAA8B;GACpC,MAAM,WAAW,MAAM,iBAAiB,QAAQ;AAChD,iBAAc,0BAA0B;GAExC,MAAM,YAAY,MAAM,iBAAiB;AAmBzC,OAAI,OAjBoB,YAAY;IAClC,IAAI;AACJ,QAAI,UAAU,SAAS,WACrB,mBAAkB;AAEpB,QAAI,UAAU,SAAS,WACrB,mBAAkB;AAEpB,QAAI,gBACF,QAAO,MAAM,cAAc;KACzB,SAAS;KACT,cAAc;KACf,CAAC;AAEJ,WAAO;OACL,EAEU;AACZ,UAAM,aAAa,SAAS;AAC5B,WAAO,WACL,4IACD;UACI;IAEL,MAAM,uBACJ,UAAU,SAAS,UACf,wBAAwB,UAAU,GAClC;IACN,MAAM,UACJ,UAAU,SAAS,UACf,yBAAyB,UAAU,GACnC;IAGN,MAAM,yBACJ,UAAU,SAAS,SACf,gCACA;IAEN,MAAM,sBACJ,UAAU,SAAS,SACf,GAAG,QAAQ,sBAAsB,qBAAqB,2BAA2B,2BACjF,UAAU,SAAS,UACjB,GAAG,QAAQ,iBAAiB,qBAAqB,2BAA2B,2BAC5E,0BAA0B;IAGlC,MAAM,cAAc,MAAM,cAAc;KACtC,SAAS,uEAAuE,MAAM,IAAI,IAAI,oBAAoB,GAAG;KACrH,cAAc;KACf,CAAC;IAEF,IAAI,gBAAgB;AAGpB,QAAI,UAAU,SAAS;SACR,cACT,OACA,MAAM,cAAc;MAClB,SACE,UAAU,SAAS,SACf,6BAA6B,QAAQ,qIACrC,6BAA6B,QAAQ;MAC3C,cAAc;MACf,CAAC,EAEI;AACR,aAAO,KACL,GAAG,MAAM,OAAO,iBAAiB,CAAC,yBACnC;AACD,YAAM,wBAAwB,SAAS,WAAW,YAAY;AAC9D,aAAO,WACL;0IAED;AACD,sBAAgB;;;AAIpB,QAAI,cACF,QAAO,aAAa,+BAA+B;AAGrD,UAAM,KAAK,kBACT,eACA,aACA,UAAU,SAAS,OACpB;AAED,WAAO,WACL,uHACD;;IAEH;;CAGN,wBAAwC;AACtC,OAAK,QACF,QAAQ,YAAY,CACpB,YACC,2GACD,CACA,aAAa,KAAK,wBAAwB,CAAC;;CAGhD,MAAgB,uBACd,SACe;AACf,QAAM,8BAA8B;AACpC,gBAAc,yBAAyB;AAEvC,SAAO,KACL,oKACD;EAGD,MAAM,YAAY,MAAM,iBAAiB;AACzC,QAAM,KAAK,kBACT,OACA,OACA,UAAU,SAAS,QACnB,QACD;AAED,SAAO,WACL,qJACD;;CAGH,MAAgB,oBACd,UACe;AACf,MAAI,CAAC,SAAS,MACZ;AAIF,QAAM,OAAO,SAAS;;;CAIxB,sBACE,aACA,gBAAyB,OACL;AACpB,SAAO;GACL,uBAAuB,iBAAiB,MACrC,QACC,QAAA,YAA4B,mBAAmB,KAAK,YAAY,CACnE;GACD,eAAe,8BAA8B,YAAY;GACzD;GACD;;;CAIH,yBACE,aACS;EACT,MAAM,EAAE,uBAAuB,kBAC7B,KAAK,sBAAsB,YAAY;AACzC,SAAO,yBAAyB;;;CAIlC,mBAA6B,cAA2C;AACtE,SAAO,CAAC,aAAa;;;CAIvB,qCACE,QACA,cACS;AACT,MAAI,OAAQ,QAAO;AACnB,MAAI,CAAC,aAAa,cAAe,QAAO;AACxC,SAAO,aAAa,yBAAyB,aAAa;;;CAI5D,4BAAsC,EACpC,iBACA,cACA,mBACsD;EACtD,MAAM,WAAqB,EAAE;AAC7B,MAAI,gBACF,UAAS,KAAK,WAAW,MAAM,KAAK,sBAAsB,CAAC;;iEAEA;AAE7D,MAAI,aAAa,cACf,UAAS,KAAK,4CAA4C,gBAAgB;;0CAEtC;AAEtC,SAAO,SAAS,SAAS,IAAI,SAAS,KAAK,KAAK,GAAG,KAAA;;CAIrD,MAAgB,kBACd,eACA,cAAuB,OACvB,SAAkB,OAClB,SACe;EACf,MAAM,iBACJ,SAAS,WACR,CAAC,UAAU,GAAG,WAAW,qBAAqB,GAC3C,uBACA;EAEN,MAAM,EAAE,eAAe,YAAY,MAAM,kBADlB,WAAW,eACuC,CAAC;EAE1E,MAAM,cAAc,MAAM,sBAAsB;EAGhD,MAAM,eAAmC,cACrC,KAAK,sBAAsB,aAAa,cAAc,GACtD;GACE,uBAAuB;GACvB,eAAe;GACf;GACD;EACL,MAAM,YACJ,aAAa,iBACb,aAAa,yBACb,aAAa;EAGf,MAAM,WAAW,OAAO,YAAY;AAClC,OAAI,CAAC,UAAW,QAAO;AACvB,OAAI,YAAa,QAAO;AACxB,OAAI,CAAC,KAAK,mBAAmB,aAAa,CAAE,QAAO;AASnD,UAAO,MARqB,aAAa;IACvC,SAAS;IACT,SAAS,CACP;KAAE,OAAO;KAAS,OAAO;KAAgB,EACzC;KAAE,OAAO;KAAO,OAAO;KAAW,CACnC;IACD,cAAc;IACf,CAAC,KACuB;MACvB;EAEJ,MAAM,yBAAyB,SAC3B,gCACA;EAeJ,MAAM,wBAXJ,aAAa,CAAC,WACV,cACE,yBACA,MAAM,WAAW;GACf,SACE;GACF,cAAc;GACf,CAAC,GACJ,OAIa,MAAM,IAAI;AAE7B,MAAI,aAAa,CAAC,UAAU;GAC1B,MAAM,kBAAkB,KAAK,qCAC3B,QACA,aACD;AACD,OAAI,gBACF,OAAM,2BACJ,QAAQ,KAAK,EACb,sBACA,QACD;GAEH,MAAM,WAAW,KAAK,4BAA4B;IAChD;IACA;IACA,iBAAiB;IAClB,CAAC;AACF,OAAI,SAAU,QAAO,QAAQ,SAAS;;EAGxC,MAAM,UAAU,CAAC,YACb,iKACA,wGAAwG,MAAM,IAC5G,8CACD;EACL,MAAM,iBACJ,eAAe,YACX,EAAE,GACF,MAAM,kBAAkB;GACtB;GACA,SAAS;IACP;KAAE,OAAO;KAAQ,OAAO,sBAAsB;KAAM;IACpD;KAAE,OAAO;KAAM,OAAO,sBAAsB;KAAI;IAChD;KAAE,OAAO;KAAO,OAAO,sBAAsB;KAAK;IAClD;KAAE,OAAO;KAAM,OAAO,sBAAsB;KAAI;IAChD;KAAE,OAAO;KAAM,OAAO,sBAAsB;KAAI;IAChD;KAAE,OAAO;KAAQ,OAAO,sBAAsB;KAAM;IAErD;GACD,UAAU,CAAC;GACZ,CAAC;EAER,MAAM,QAAsB,EAAE;AAC9B,OAAK,MAAM,iBAAiB,gBAAgB;GAC1C,MAAM,QAAQ,sBAAsB;AAOpC,SAAM,iBAAiB,EACrB,SAAS,kBAAkB,MAPT,mBAAmB;IACrC;IACA,SAAS,GAAG,MAAM,KAAK,sBAAsB,eAAe,CAAC,+EAA+E,sBAAsB,eAAe;IACjL,cAAc,mBAAmB;IAClC,CAAC,CAGiC,EAClC;;AAIH,MAAI,aAAa,CAAC,SAChB,OAAM,KAAK,EACT,QAAQ,KAAK,KAAK,sBAAsB,gBAAgB,EACzD;AAIH,QAAM,qBAAqB,gBAAgB;GACzC;GACA;GACA,KAAK,SAAS;GACd,OAAO,OAAO,KAAK,MAAM,CAAC,SAAS,IAAI,QAAQ,KAAA;GAC/C,WAAW,SAAS,SAAS,KAAA;GAC7B,SAAS,aAAa;GACtB,cAAc,aAAa,iBAAiB,CAAC;GAC9C,CAAC;AAEF,SAAO,QACL,QAAQ,MAAM,KACZ,eACD,CAAC,sGACH;AAED,MAAI,iBAAiB,OACnB,OAAM,aAAa;GACjB,cAAc,QAAQ,KAAK;GAC3B;GACA;GACA;GACA,iBAAiB,WAAW,KAAA,IAAY;GACzC,CAAC;AAQJ,MAAI,EAJmB,cACnB,mBAAmB,MAAM,aAAa,MAAM,KAAK,GACjD,SAEmB,EAAE,aAAa,SAAS;GAC7C,MAAM,iBAAiB,MAAM,mBAAmB;GAChD,MAAM,UAAU,OAAO,eAAe;AACtC,WAAQ,MACN,0CAA0C,eAAe,KAAK,KAC/D;AACD,SAAM,eAAe,MAAM,gBAAgB,KAAK;AAChD,WAAQ,KAAK,MAAM,MAAM,gBAAgB,CAAC;;AAI5C,OAAK,CAAC,UAAU,CAAC,aAAa,aAAa,CAAC,mBAAmB;OACvC,cAClB,OACA,MAAM,cAAc;IAClB,SACE;IACF,cAAc;IACf,CAAC,EACa;IACjB,MAAM,WAAW,MAAM,iBAAiB,EAAE,CAAC;AAa3C,UAAM,eAAe,MADK,oBAAoB,UAX9B,cACZ,QACA,MAAM,aAAmD;KACvD,SAAS;KACT,SAAS;MACP;OAAE,OAAO;OAAe,OAAO;OAAe;MAC9C;OAAE,OAAO;OAAc,OAAO;OAAc;MAC5C;OAAE,OAAO;OAAO,OAAO;OAAQ;MAChC;KACD,cAAc;KACf,CAAC,CAC0D,EAC9B,SAAS,SAAS,SAAS,UAAU;;;;CAI7E,MAAgB,mBAAmB,SAAsC;EACvE,MAAM,WAAW,MAAM,iBAAiB,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAGnE,QAAM,eAAe,MADK,oBAAoB,UAD9B,QAAQ,WAAW,MAC6B,EAC9B,SAAS,UAAU"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/cli/base.ts"],"sourcesContent":["import { Command } from 'commander';\nimport {\n DEFAULT_TRANSLATIONS_DIR,\n DEFAULT_VITE_TRANSLATIONS_DIR,\n} from '../utils/constants.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport {\n displayHeader,\n promptText,\n logErrorAndExit,\n exitSync,\n promptConfirm,\n promptMultiSelect,\n promptSelect,\n promptGlobPatterns,\n} from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { lottieTranslateError } from '../console/index.js';\nimport { parseGlobPatterns } from '../console/promptParsing.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {\n FilesOptions,\n Settings,\n SupportedLibraries,\n SetupOptions,\n TranslateFlags,\n SharedFlags,\n} from '../types/index.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport chalk from 'chalk';\nimport { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';\nimport { handleSetupReactCommand } from '../setup/wizard.js';\nimport {\n isPackageInstalled,\n searchForPackageJson,\n} from '../utils/packageJson.js';\nimport { getDesiredLocales } from '../setup/userInput.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { retrieveCredentials, setCredentials } from '../utils/credentials.js';\nimport { areCredentialsSet } from '../utils/credentials.js';\nimport { upload } from './commands/upload.js';\nimport { attachSharedFlags, attachTranslateFlags } from './flags.js';\nimport { handleStage } from './commands/stage.js';\nimport { handleSetupProject } from './commands/setupProject.js';\nimport { handleDownload } from './commands/download.js';\nimport {\n handleTranslate,\n postProcessTranslations,\n} from './commands/translate.js';\nimport {\n getNeedsPostprocessing,\n clearDownloaded,\n} from '../state/recentDownloads.js';\nimport { clearWarnings } from '../state/translateWarnings.js';\nimport { displayTranslateSummary } from '../console/displayTranslateSummary.js';\nimport updateConfig from '../fs/config/updateConfig.js';\nimport { loadConfig } from '../fs/config/loadConfig.js';\nimport { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';\nimport { saveLocalEdits } from '../api/saveLocalEdits.js';\nimport {\n hasValidApiKey,\n hasValidCredentials,\n} from './commands/utils/validation.js';\nimport processSharedStaticAssets, {\n mirrorAssetsToLocales,\n} from '../utils/sharedStaticAssets.js';\nimport { setupLocadex } from '../locadex/setupFlow.js';\nimport { detectFramework } from '../setup/detectFramework.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from '../setup/frameworkUtils.js';\nimport { INLINE_LIBRARIES, Libraries } from '../types/libraries.js';\nimport { handleEnqueue } from './commands/enqueue.js';\nimport { splitMintlifyLanguageRefs } from '../utils/splitMintlifyLanguageRefs.js';\nimport { runMergeDriver } from '../git/mergeDrivers.js';\nimport { setupGitMergeDrivers } from '../git/setupMergeDrivers.js';\nimport { warnReactPackageCompatibility } from '../utils/reactPackageCompatibility.js';\nimport {\n createDiagnosticMessage,\n formatDiagnosticErrorDetails,\n} from 'generaltranslation/internal';\nimport { setupViteSPA } from '../setup/setupViteSPA.js';\nimport { manifestDirectlyDeclaresGTVue } from '@generaltranslation/vue-extractor/integration';\nimport { api } from '../utils/api.js';\nimport { handleApiCommand, type ApiCommandOptions } from './commands/api.js';\n\nconst ID_COMPATIBILITY_WARNING_COMMANDS = new Set([\n 'download',\n 'enqueue',\n 'generate',\n 'setup',\n 'stage',\n 'translate',\n 'validate',\n]);\nconst workspaceRootSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The setup wizard cannot run from a monorepo workspace root',\n why: 'GT must be configured in the specific app you want to localize',\n fix: \"Change to that app's directory and rerun `npx gt@latest`\",\n});\nfunction createProjectCommandError(\n whatHappened: string,\n error: unknown\n): string {\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened,\n details: formatDiagnosticErrorDetails(error),\n });\n}\n\nconst electronSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened:\n 'The automatic setup wizard is not ready for Electron applications',\n docsUrl: 'https://generaltranslation.com/docs/react',\n});\n\nasync function exitIfUnsupportedSetupTarget(): Promise<void> {\n const packageJson = await searchForPackageJson();\n if (packageJson && isPackageInstalled('electron', packageJson, false, true)) {\n logErrorAndExit(electronSetupError);\n }\n if (\n fs.existsSync(path.join(process.cwd(), 'pnpm-workspace.yaml')) ||\n packageJson?.workspaces\n ) {\n logErrorAndExit(workspaceRootSetupError);\n }\n}\n\nexport type UploadOptions = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n defaultLocale?: string;\n};\n\nexport type LoginOptions = {\n config?: string;\n keyType?: 'development' | 'production' | 'all';\n};\n\nexport type GitSetupOptions = {\n config?: string;\n dryRun?: boolean;\n omitConfigIds?: boolean;\n driverCommand?: string;\n};\n\ntype LocalTranslationGuidanceOptions = {\n generatedLoader: boolean;\n runtimeSetup: InlineRuntimeSetup;\n translationsDir: string;\n};\n\ntype InlineRuntimeSetup = {\n hasOtherInlineRuntime: boolean;\n hasVueRuntime: boolean;\n ranReactSetup: boolean;\n};\n\nexport class BaseCLI {\n protected library: SupportedLibraries;\n protected additionalModules: SupportedLibraries[];\n protected program: Command;\n // Constructor is shared amongst all CLI class types\n public constructor(\n program: Command,\n library: SupportedLibraries,\n additionalModules?: SupportedLibraries[]\n ) {\n this.program = program;\n this.library = library;\n this.additionalModules = additionalModules || [];\n\n this.program.option(\n '--skip-version-check',\n 'Skip the monorepo GT package version consistency check'\n );\n this.program.option(\n '--suppress-id-compatibility-warning',\n 'Suppress the React package ID compatibility warning'\n );\n this.program.option(\n '-q, --quiet',\n 'Suppress informational output; only warnings and errors are shown'\n );\n // Apply --quiet before any other hook or command action runs so the\n // singleton logger is muted for the rest of the invocation. The flag is a\n // global root option, so commander resolves it in any position and for\n // nested commands (e.g. `gt git setup --quiet`).\n this.program.hook('preAction', () => {\n logger.setQuiet(Boolean(this.program.opts().quiet));\n });\n this.program.hook('preAction', async (thisCommand, actionCommand) => {\n // Nested commands (e.g. `gt git setup`) can share leaf names with\n // translation commands; only direct children of the root qualify\n if (actionCommand.parent !== thisCommand) return;\n if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;\n await warnReactPackageCompatibility(\n Boolean(this.program.opts().suppressIdCompatibilityWarning)\n );\n });\n\n this.setupInitCommand();\n this.setupConfigureCommand();\n this.setupUploadCommand();\n this.setupLoginCommand();\n this.setupSendDiffsCommand();\n this.setupApiCommand();\n this.setupProjectCommands();\n this.setupGitCommand();\n }\n // Init is never called in a child class\n public init() {\n this.setupSetupProjectCommand();\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n // Execute is called by the main program\n public execute() {\n // If no command is specified, run 'init'\n if (process.argv.length <= 2) {\n process.argv.push('init');\n }\n }\n\n protected setupSetupProjectCommand(): void {\n attachTranslateFlags(\n this.program\n .command('setup')\n .description(\n 'Upload source files and setup the project for translation'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Uploading source files and setting up project...');\n await this.handleSetupProject(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupStageCommand(): void {\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupEnqueueCommand(): void {\n attachTranslateFlags(\n this.program\n .command('enqueue')\n .description('Enqueues translations for a given set of files')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Enqueuing translations...');\n await this.handleEnqueue(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupDownloadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('download')\n .description('Download translations that were originally staged')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Downloading translations...');\n await this.handleDownload(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachTranslateFlags(\n this.program\n .command('translate')\n .description('Translate your project using General Translation')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Starting translation...');\n await this.handleTranslate(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupSendDiffsCommand(): void {\n attachSharedFlags(\n this.program\n .command('save-local')\n .description(\n 'Save local edits for all configured files by sending diffs (no translation enqueued)'\n )\n )\n .option('--publish', 'Publish translations to the CDN', false)\n .action(async (initOptions: SharedFlags) => {\n displayHeader('Saving local edits...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n if (!hasValidCredentials(settings)) return exitSync(1);\n await saveLocalEdits(settings);\n logger.endCommand('Saved local edits');\n });\n }\n\n protected setupApiCommand(): void {\n attachSharedFlags(\n this.program\n .command('api [endpoint]')\n .description('Make an authenticated request to the GT API')\n .option('-X, --method <method>', 'HTTP method', 'GET')\n .option('--input <file>', 'Request body file, or - for standard input')\n .option(\n '-H, --header <header>',\n 'Request header in \"Key: Value\" format',\n (header, headers: string[] | undefined) => [\n ...(headers ?? []),\n header,\n ]\n )\n .option('-i, --include', 'Include response status and headers')\n .option('--spec', 'Print the bundled OpenAPI specification')\n ).action((endpoint, options: ApiCommandOptions) =>\n handleApiCommand(endpoint, options)\n );\n }\n\n protected setupProjectCommands(): void {\n const projectCommand = this.program\n .command('project')\n .description('Manage General Translation projects');\n\n attachSharedFlags(\n projectCommand\n .command('create')\n .description(\n 'Create a General Translation project using an organization API key'\n )\n .requiredOption('--org-id <orgId>', 'Organization ID')\n .requiredOption('--name <name>', 'Project name')\n .requiredOption('--default-locale <locale>', 'Project default locale')\n .option('--cdn-enabled', 'Enable CDN delivery', false)\n ).action(async (options) => {\n try {\n const settings = await generateSettings(options);\n // Project creation uses an organization key before a project ID exists.\n if (!hasValidApiKey(settings)) return exitSync(1);\n const { project } = await api.createProject(options.orgId, {\n name: options.name,\n defaultLocale: options.defaultLocale,\n cdnEnabled: options.cdnEnabled,\n });\n logger.info(`Created ${project.name} (${project.id})`);\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError('Failed to create the project', error)\n );\n }\n });\n\n attachSharedFlags(\n projectCommand\n .command('status')\n .description('Check the status of a project setup job')\n .argument('<job-id>', 'Setup job ID')\n ).action(async (jobId, options) => {\n try {\n const settings = await generateSettings(options);\n if (!hasValidCredentials(settings)) return exitSync(1);\n const [status] = await api.checkJobStatus([jobId]);\n logger.info(status?.status ?? 'unknown');\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError(\n 'Failed to check the project setup status',\n error\n )\n );\n }\n });\n }\n\n protected setupGitCommand(): void {\n const gitCommand = this.program\n .command('git')\n .description('Configure Git integrations for General Translation');\n\n gitCommand\n .command('setup')\n .description('Set up GT merge drivers for generated translation files')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option('--dry-run', 'Print changes without writing files', false)\n .option(\n '--omit-config-ids',\n 'Persist omitConfigIds and remove generated config IDs'\n )\n .option(\n '--driver-command <command>',\n 'Command Git should use to invoke gt, e.g. \"pnpm exec gt\"'\n )\n .action(async (options: GitSetupOptions) => {\n displayHeader('Setting up GT Git merge drivers...');\n const settings = await generateSettings(options, undefined, {\n requireConfig: true,\n });\n const omitConfigIds = await this.resolveGitSetupOmitConfigIds(\n options,\n settings\n );\n const result = await setupGitMergeDrivers(settings, {\n dryRun: options.dryRun,\n omitConfigIds,\n driverCommand: options.driverCommand,\n });\n\n for (const line of result.addedAttributes) {\n logger.step(\n `${options.dryRun ? 'Would add' : 'Added'} ${chalk.cyan(\n line\n )} to ${chalk.cyan(result.gitattributesPath)}`\n );\n }\n if (result.addedAttributes.length === 0) {\n logger.info(`${chalk.cyan('.gitattributes')} is already configured.`);\n }\n\n for (const args of result.gitConfigCommands) {\n logger.step(\n `${options.dryRun ? 'Would run' : 'Configured'} ${chalk.cyan(\n `git config --local ${args.join(' ')}`\n )}`\n );\n }\n\n if (result.updatedConfig) {\n logger.step(\n `${options.dryRun ? 'Would persist' : 'Persisted'} ${chalk.cyan(\n 'omitConfigIds: true'\n )} in ${chalk.cyan(settings.config)}`\n );\n } else if (options.dryRun && !settings.omitConfigIds) {\n logger.info(\n `Run without ${chalk.cyan('--dry-run')} to be prompted to persist ${chalk.cyan(\n 'omitConfigIds: true'\n )}, or pass ${chalk.cyan('--omit-config-ids')}.`\n );\n }\n\n for (const warning of result.warnings) {\n logger.warn(chalk.yellow(warning));\n }\n\n logger.endCommand(\n options.dryRun\n ? 'Dry run complete.'\n : 'GT Git merge drivers configured.'\n );\n });\n\n gitCommand\n .command('merge-driver', { hidden: true })\n .argument('<driver>', 'Merge driver name')\n .argument('<base>', 'Common ancestor file')\n .argument('<ours>', 'Current branch file')\n .argument('<theirs>', 'Incoming branch file')\n .argument('[path]', 'Merged path')\n .action((driver: string, base: string, ours: string, theirs: string) => {\n if (driver !== 'gt-lock' && driver !== 'gtjson') {\n logger.error(`Unknown GT merge driver: ${driver}`);\n exitSync(1);\n }\n const result = runMergeDriver(driver, base, ours, theirs);\n if (!result.ok) {\n logger.error(result.reason);\n exitSync(1);\n }\n });\n }\n\n protected async resolveGitSetupOmitConfigIds(\n options: GitSetupOptions,\n settings: Settings\n ): Promise<boolean> {\n if (options.omitConfigIds) return true;\n // Already opted in: persist again so stale config IDs still get removed\n if (settings.omitConfigIds) return true;\n if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {\n return false;\n }\n return promptConfirm({\n message:\n 'Also set omitConfigIds: true to reduce gt.config.json merge conflicts?',\n defaultValue: true,\n });\n }\n\n protected async handleSetupProject(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n await handleSetupProject(initOptions, settings, this.library);\n }\n\n protected async handleStage(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Update settings.stageTranslations to true\n settings.stageTranslations = true;\n await updateConfig(settings.config, {\n stageTranslations: true,\n });\n }\n await handleStage(initOptions, settings, this.library, true);\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleEnqueue(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleEnqueue(initOptions, settings, this.library);\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleDownload(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleDownload(initOptions, settings, this.library);\n }\n\n protected async handleTranslate(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Lottie translations finish asynchronously server-side (layout\n // refinement runs after the translation job completes), so the immediate\n // translate flow would try to download them before they're ready. Only\n // the stage + download flow supports them.\n if (settings.files?.resolvedPaths.lottie?.length) {\n return logErrorAndExit(lottieTranslateError);\n }\n const results = await handleStage(\n initOptions,\n settings,\n this.library,\n false\n );\n if (results) {\n await handleTranslate(\n initOptions,\n settings,\n results.fileVersionData,\n results.jobData,\n results.branchData,\n results.publishMap,\n results.inlineLibrary\n );\n }\n } else {\n await handleDownload(initOptions, settings, this.library);\n }\n // Only postprocess files downloaded in this run\n const include = getNeedsPostprocessing();\n if (include.size > 0) {\n await postProcessTranslations(settings, include);\n }\n // Split Mintlify language entries into $ref files to keep docs.json small\n await splitMintlifyLanguageRefs(settings);\n // Mirror assets after translations are downloaded and locale dirs are populated\n await mirrorAssetsToLocales(settings);\n clearDownloaded();\n displayTranslateSummary();\n clearWarnings();\n }\n\n protected setupUploadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('upload')\n .description(\n 'Upload source files and translations to the General Translation platform'\n )\n ).action(async (initOptions: UploadOptions) => {\n displayHeader('Starting upload...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const options = { ...initOptions, ...settings };\n\n await this.handleUploadCommand(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupLoginCommand(): void {\n this.program\n .command('auth')\n .description('Generate General Translation API keys and project ID')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option(\n '-t, --key-type <type>',\n 'Type of key to generate, production | development | all'\n )\n .action(async (options: LoginOptions) => {\n displayHeader('Authenticating with General Translation...');\n if (!options.keyType) {\n options.keyType = await promptSelect<\n 'development' | 'production' | 'all'\n >({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n } else {\n if (\n options.keyType !== 'development' &&\n options.keyType !== 'production' &&\n options.keyType !== 'all'\n ) {\n logErrorAndExit(\n 'Invalid key type, must be development, production, or all'\n );\n }\n }\n await this.handleLoginCommand(options);\n logger.endCommand(\n `Done! ${options.keyType} keys have been generated and saved to your .env.local file.`\n );\n });\n }\n\n protected setupInitCommand(): void {\n this.program\n .command('init')\n .description(\n 'Run the setup wizard to configure your project for General Translation'\n )\n .option(\n '--src <paths...>',\n \"Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'\"\n )\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .action(async (options: SetupOptions) => {\n await exitIfUnsupportedSetupTarget();\n const settings = await generateSettings(options);\n displayHeader('Running setup wizard...');\n\n const framework = await detectFramework();\n\n const useAgent = await (async () => {\n let useAgentMessage;\n if (framework.name === 'mintlify') {\n useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;\n }\n if (framework.name === 'next-app') {\n useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;\n }\n if (useAgentMessage) {\n return await promptConfirm({\n message: useAgentMessage,\n defaultValue: false,\n });\n }\n return false;\n })();\n\n if (useAgent) {\n await setupLocadex(settings);\n logger.endCommand(\n 'Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex'\n );\n } else {\n // Get framework display info for the defaults message\n const frameworkDisplayName =\n framework.type === 'react'\n ? getFrameworkDisplayName(framework)\n : null;\n const library =\n framework.type === 'react'\n ? getReactFrameworkLibrary(framework)\n : null;\n\n // Build defaults description based on detected framework\n const defaultTranslationsDir =\n framework.name === 'vite'\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n const defaultsDescription =\n framework.name === 'vite'\n ? `${library} & initializeGTSPA, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : framework.type === 'react'\n ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : `Files saved locally in ${defaultTranslationsDir}`;\n\n // Ask if user wants to use defaults\n const useDefaults = await promptConfirm({\n message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,\n defaultValue: true,\n });\n\n let ranReactSetup = false;\n\n // so that people can run init in non-js projects\n if (framework.type === 'react') {\n const wrap = useDefaults\n ? true\n : await promptConfirm({\n message:\n framework.name === 'vite'\n ? `Would you like to install ${library} and configure initializeGTSPA? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n : `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n\n if (wrap) {\n logger.info(\n `${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`\n );\n await handleSetupReactCommand(options, framework, useDefaults);\n logger.endCommand(\n `Done! Since this wizard is experimental, please review the changes and make modifications as needed.\n\\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n );\n ranReactSetup = true;\n }\n }\n\n if (ranReactSetup) {\n logger.startCommand('Setting up project config...');\n }\n // Configure gt.config.json\n await this.handleInitCommand(\n ranReactSetup,\n useDefaults,\n framework.name === 'vite'\n );\n\n logger.endCommand(\n 'Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs'\n );\n }\n });\n }\n\n protected setupConfigureCommand(): void {\n this.program\n .command('configure')\n .description(\n 'Configure your project for General Translation. This will create a gt.config.json file in your codebase.'\n )\n .action(() => this.handleConfigureCommand());\n }\n\n protected async handleConfigureCommand(\n options?: SetupOptions\n ): Promise<void> {\n await exitIfUnsupportedSetupTarget();\n displayHeader('Configuring project...');\n\n logger.info(\n 'Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.'\n );\n\n // Configure gt.config.json\n const framework = await detectFramework();\n await this.handleInitCommand(\n false,\n false,\n framework.name === 'vite',\n options\n );\n\n logger.endCommand(\n 'Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard'\n );\n }\n\n protected async handleUploadCommand(\n settings: Settings & UploadOptions\n ): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n // Process all file types at once with a single call\n await upload(settings);\n }\n\n /** Describes installed runtimes without changing historical package lookup. */\n protected getInlineRuntimeSetup(\n packageJson: Record<string, unknown>,\n ranReactSetup: boolean = false\n ): InlineRuntimeSetup {\n return {\n hasOtherInlineRuntime: INLINE_LIBRARIES.some(\n (lib) =>\n lib !== Libraries.GT_VUE && isPackageInstalled(lib, packageJson)\n ),\n hasVueRuntime: manifestDirectlyDeclaresGTVue(packageJson),\n ranReactSetup,\n };\n }\n\n /** Returns whether any inline runtime is installed for setup. */\n protected isInlineRuntimeInstalled(\n packageJson: Record<string, unknown>\n ): boolean {\n const { hasOtherInlineRuntime, hasVueRuntime } =\n this.getInlineRuntimeSetup(packageJson);\n return hasOtherInlineRuntime || hasVueRuntime;\n }\n\n /** Returns whether every installed runtime can consume CDN translations. */\n protected supportsCDNStorage(runtimeSetup: InlineRuntimeSetup): boolean {\n return !runtimeSetup.hasVueRuntime;\n }\n\n /** Returns whether setup should generate a local runtime loader. */\n protected shouldGenerateLocalTranslationLoader(\n isVite: boolean,\n runtimeSetup: InlineRuntimeSetup\n ): boolean {\n if (isVite) return false;\n if (!runtimeSetup.hasVueRuntime) return true;\n return runtimeSetup.hasOtherInlineRuntime || runtimeSetup.ranReactSetup;\n }\n\n /** Returns framework guidance after selecting local translation storage. */\n protected getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir,\n }: LocalTranslationGuidanceOptions): string | undefined {\n const guidance: string[] = [];\n if (generatedLoader) {\n guidance.push(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.\nMake sure to add this function to your app configuration.\nSee https://generaltranslation.com/en/docs/next/guides/local-tx`);\n }\n if (runtimeSetup.hasVueRuntime) {\n guidance.push(`GT will write local translation files to ${translationsDir}.\nConfigure createGT({ loadTranslations }) to load files from that directory.\nSee https://www.npmjs.com/package/gt-vue`);\n }\n return guidance.length > 0 ? guidance.join('\\n') : undefined;\n }\n\n // Wizard for configuring gt.config.json\n protected async handleInitCommand(\n ranReactSetup: boolean,\n useDefaults: boolean = false,\n isVite: boolean = false,\n options?: SetupOptions\n ): Promise<void> {\n const configFilepath =\n options?.config ||\n (!isVite && fs.existsSync('src/gt.config.json')\n ? 'src/gt.config.json'\n : 'gt.config.json');\n const existingConfig = loadConfig(configFilepath);\n const { defaultLocale, locales } = await getDesiredLocales(existingConfig);\n\n const packageJson = await searchForPackageJson();\n\n // Ask if using another i18n library\n const runtimeSetup: InlineRuntimeSetup = packageJson\n ? this.getInlineRuntimeSetup(packageJson, ranReactSetup)\n : {\n hasOtherInlineRuntime: false,\n hasVueRuntime: false,\n ranReactSetup,\n };\n const isUsingGT =\n runtimeSetup.ranReactSetup ||\n runtimeSetup.hasOtherInlineRuntime ||\n runtimeSetup.hasVueRuntime;\n\n // Ask where the translations are stored\n const usingCDN = await (async () => {\n if (!isUsingGT) return false;\n if (useDefaults) return false; // Default to local\n if (!this.supportsCDNStorage(runtimeSetup)) return false;\n const selectedValue = await promptSelect({\n message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,\n options: [\n { value: 'local', label: 'Save locally' },\n { value: 'cdn', label: 'Use CDN' },\n ],\n defaultValue: 'local',\n });\n return selectedValue === 'cdn';\n })();\n\n const defaultTranslationsDir = isVite\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n // Ask where the translations are stored\n const translationsDir =\n isUsingGT && !usingCDN\n ? useDefaults\n ? defaultTranslationsDir\n : await promptText({\n message:\n 'What is the path to the directory where you would like to store your translation files?',\n defaultValue: defaultTranslationsDir,\n })\n : null;\n\n // Determine final translations directory with fallback\n const finalTranslationsDir =\n translationsDir?.trim() || defaultTranslationsDir;\n\n if (isUsingGT && !usingCDN) {\n const generatedLoader = this.shouldGenerateLocalTranslationLoader(\n isVite,\n runtimeSetup\n );\n if (generatedLoader) {\n await createLoadTranslationsFile(\n process.cwd(),\n finalTranslationsDir,\n locales\n );\n }\n const guidance = this.getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir: finalTranslationsDir,\n });\n if (guidance) logger.message(guidance);\n }\n\n const message = !isUsingGT\n ? 'What is the format of your language resource files? Select as many as applicable.\\nAdditionally, you can translate any other files you have in your project.'\n : `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim(\n '(To continue without selecting press Enter)'\n )}`;\n const fileExtensions =\n useDefaults && isUsingGT\n ? [] // Skip for GT projects when using defaults\n : await promptMultiSelect({\n message,\n options: [\n { value: 'json', label: FILE_EXT_TO_EXT_LABEL.json },\n { value: 'md', label: FILE_EXT_TO_EXT_LABEL.md },\n { value: 'mdx', label: FILE_EXT_TO_EXT_LABEL.mdx },\n { value: 'ts', label: FILE_EXT_TO_EXT_LABEL.ts },\n { value: 'js', label: FILE_EXT_TO_EXT_LABEL.js },\n { value: 'yaml', label: FILE_EXT_TO_EXT_LABEL.yaml },\n // TWILIO_CONTENT_JSON not supported in CLI init as its too niche\n ],\n required: !isUsingGT,\n });\n\n const files: FilesOptions = {};\n for (const fileExtension of fileExtensions) {\n const label = FILE_EXT_TO_EXT_LABEL[fileExtension];\n const paths = await promptGlobPatterns({\n label,\n message: `${chalk.cyan(FILE_EXT_TO_EXT_LABEL[fileExtension])}: Enter a space-separated list of glob patterns matching the location of the ${FILE_EXT_TO_EXT_LABEL[fileExtension]} files you would like to translate.\\nMake sure to include [locale] in the patterns.\\nSee https://generaltranslation.com/docs/cli/reference/config#include for more information.`,\n defaultValue: `./**/[locale]/*.${fileExtension}`,\n });\n\n files[fileExtension] = {\n include: parseGlobPatterns(paths),\n };\n }\n\n // Add GT translations if using GT and storing locally\n if (isUsingGT && !usingCDN) {\n files.gt = {\n output: path.join(finalTranslationsDir, `[locale].json`),\n };\n }\n\n // Create gt.config.json\n await createOrUpdateConfig(configFilepath, {\n defaultLocale,\n locales,\n src: options?.src,\n files: Object.keys(files).length > 0 ? files : undefined,\n framework: isVite ? 'vite' : undefined,\n publish: isUsingGT && usingCDN,\n clearPublish: runtimeSetup.hasVueRuntime && !usingCDN,\n });\n\n logger.success(\n `Edit ${chalk.cyan(\n configFilepath\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n if (ranReactSetup && isVite) {\n await setupViteSPA({\n appDirectory: process.cwd(),\n configFilepath,\n defaultLocale,\n locales,\n translationsDir: usingCDN ? undefined : finalTranslationsDir,\n });\n }\n\n // Install gt if not installed\n const isCLIInstalled = packageJson\n ? isPackageInstalled('gt', packageJson, true, true)\n : true; // if no package.json, we can't install it\n\n if (!isCLIInstalled && !(isUsingGT && isVite)) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner();\n spinner.start(\n `Installing gt as a dev dependency with ${packageManager.name}...`\n );\n await installPackage('gt', packageManager, true);\n spinner.stop(chalk.green('Installed gt.'));\n }\n\n // Set credentials\n if ((!isVite || !isUsingGT || usingCDN) && !areCredentialsSet()) {\n const loginQuestion = useDefaults\n ? true\n : await promptConfirm({\n message:\n 'Would you like the wizard to automatically generate API keys and a project ID for you?',\n defaultValue: true,\n });\n if (loginQuestion) {\n const settings = await generateSettings({});\n const keyType = useDefaults\n ? 'all'\n : await promptSelect<'development' | 'production' | 'all'>({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, isVite ? 'vite' : settings.framework);\n }\n }\n }\n protected async handleLoginCommand(options: LoginOptions): Promise<void> {\n const settings = await generateSettings({ config: options.config });\n const keyType = options.keyType || 'all';\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { logger } from "../../console/logger.js";
2
+ import { gt } from "../../utils/gt.js";
2
3
  import { exitSync, logErrorAndExit } from "../../console/logging.js";
3
4
  import { getRelative, readFile } from "../../fs/findFilepath.js";
4
5
  import { fileEncodingSkipReason, noDefaultLocaleError } from "../../console/index.js";
@@ -10,6 +11,7 @@ import { runUploadFilesWorkflow } from "../../workflows/upload.js";
10
11
  import { createFileMapping } from "../../formats/files/fileMapping.js";
11
12
  import { hasValidCredentials } from "./utils/validation.js";
12
13
  import { runPublishWorkflow } from "../../workflows/publish.js";
14
+ import { parseXcstringsCatalog, serializeXcstringsSlice, sliceTranslationCatalog } from "../../formats/xcstrings/parseXcstrings.js";
13
15
  import { aggregateFiles } from "../../formats/files/aggregateFiles.js";
14
16
  import { existsSync } from "node:fs";
15
17
  //#region src/cli/commands/upload.ts
@@ -23,17 +25,21 @@ async function upload(settings) {
23
25
  const additionalOptions = settings.options || {};
24
26
  const { resolvedPaths: filePaths, placeholderPaths, transformPaths, transformFormats } = settings.files;
25
27
  const { files: allFiles, publishMap } = await aggregateFiles(settings);
28
+ const sourceFileNames = new Set(allFiles.map((file) => file.fileName));
26
29
  const compositeJsonFiles = /* @__PURE__ */ new Map();
27
- if (filePaths.json) {
28
- const sourceFileNames = new Set(allFiles.map((file) => file.fileName));
29
- for (const filePath of filePaths.json) {
30
- const relativePath = getRelative(filePath);
31
- if (!sourceFileNames.has(relativePath)) continue;
32
- if (validateJsonSchema(additionalOptions, filePath)?.composite) compositeJsonFiles.set(relativePath, {
33
- filePath,
34
- content: readFile(filePath)
35
- });
36
- }
30
+ if (filePaths.json) for (const filePath of filePaths.json) {
31
+ const relativePath = getRelative(filePath);
32
+ if (!sourceFileNames.has(relativePath)) continue;
33
+ if (validateJsonSchema(additionalOptions, filePath)?.composite) compositeJsonFiles.set(relativePath, {
34
+ filePath,
35
+ content: readFile(filePath)
36
+ });
37
+ }
38
+ const xcstringsCatalogs = /* @__PURE__ */ new Map();
39
+ if (filePaths.xcstrings) for (const filePath of filePaths.xcstrings) {
40
+ const relativePath = getRelative(filePath);
41
+ if (!sourceFileNames.has(relativePath)) continue;
42
+ xcstringsCatalogs.set(relativePath, parseXcstringsCatalog(readFile(filePath)));
37
43
  }
38
44
  if (allFiles.length === 0) {
39
45
  logger.error("No files to upload were found. Check your configuration and try again.");
@@ -47,7 +53,20 @@ async function upload(settings) {
47
53
  const sourceFile = { ...file };
48
54
  const translations = [];
49
55
  const compositeInfo = compositeJsonFiles.get(file.fileName);
50
- for (const locale of locales) if (compositeInfo) {
56
+ const xcstringsCatalog = xcstringsCatalogs.get(file.fileName);
57
+ for (const locale of locales) if (xcstringsCatalog) {
58
+ const slice = sliceTranslationCatalog(xcstringsCatalog, gt.resolveCanonicalLocale(locale));
59
+ if (!slice) continue;
60
+ translations.push({
61
+ content: serializeXcstringsSlice(slice),
62
+ fileName: file.fileName,
63
+ fileFormat: file.transformFormat ?? file.fileFormat,
64
+ dataFormat: file.dataFormat,
65
+ locale,
66
+ fileId: file.fileId,
67
+ versionId: file.versionId
68
+ });
69
+ } else if (compositeInfo) {
51
70
  const extracted = extractJson(compositeInfo.content, compositeInfo.filePath, additionalOptions, locale, settings.defaultLocale);
52
71
  if (extracted) translations.push({
53
72
  content: extracted,
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","names":[],"sources":["../../../src/cli/commands/upload.ts"],"sourcesContent":["import {\n fileEncodingSkipReason,\n noDefaultLocaleError,\n} from '../../console/index.js';\nimport { exitSync, logErrorAndExit } from '../../console/logging.js';\nimport { logger } from '../../console/logger.js';\nimport { getRelative, readFile } from '../../fs/findFilepath.js';\nimport { readFileContent } from '../../fs/fileContent.js';\nimport { Settings } from '../../types/index.js';\nimport { UploadOptions } from '../base.js';\nimport { extractJson } from '../../formats/json/extractJson.js';\nimport { validateJsonSchema } from '../../formats/json/utils.js';\nimport { runUploadFilesWorkflow } from '../../workflows/upload.js';\nimport { existsSync } from 'node:fs';\nimport { createFileMapping } from '../../formats/files/fileMapping.js';\nimport type { FileToUpload } from 'generaltranslation/types';\nimport { hasValidCredentials } from './utils/validation.js';\nimport { runPublishWorkflow } from '../../workflows/publish.js';\nimport { aggregateFiles } from '../../formats/files/aggregateFiles.js';\nimport { recordWarning } from '../../state/translateWarnings.js';\n\n/**\n * Sends multiple files to the API for translation\n * @param settings - Translation options including API settings\n * @returns Promise that resolves when translation is complete\n */\nexport async function upload(\n settings: Settings & UploadOptions\n): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n const additionalOptions = settings.options || {};\n const {\n resolvedPaths: filePaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n } = settings.files;\n\n // Reuse the same source aggregation path as translate/stage so source\n // parsing behavior stays consistent across commands.\n const { files: allFiles, publishMap } = await aggregateFiles(settings);\n const compositeJsonFiles = new Map<\n string,\n { filePath: string; content: string }\n >();\n\n if (filePaths.json) {\n const sourceFileNames = new Set(allFiles.map((file) => file.fileName));\n for (const filePath of filePaths.json) {\n const relativePath = getRelative(filePath);\n if (!sourceFileNames.has(relativePath)) continue;\n\n const jsonSchema = validateJsonSchema(additionalOptions, filePath);\n if (jsonSchema?.composite) {\n compositeJsonFiles.set(relativePath, {\n filePath,\n content: readFile(filePath),\n });\n }\n }\n }\n\n if (allFiles.length === 0) {\n logger.error(\n 'No files to upload were found. Check your configuration and try again.'\n );\n return;\n }\n\n if (!settings.defaultLocale) {\n return logErrorAndExit(noDefaultLocaleError);\n }\n if (!hasValidCredentials(settings)) return exitSync(1);\n\n const locales = settings.locales || [];\n // Create file mapping for all file types\n const fileMapping = createFileMapping(\n filePaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n locales,\n settings.defaultLocale\n );\n\n // construct object\n const uploadData = allFiles.map((file) => {\n const sourceFile: FileToUpload = { ...file };\n\n const translations: FileToUpload[] = [];\n const compositeInfo = compositeJsonFiles.get(file.fileName);\n\n for (const locale of locales) {\n if (compositeInfo) {\n // Composite JSON: extract translations from the same source file\n const extracted = extractJson(\n compositeInfo.content,\n compositeInfo.filePath,\n additionalOptions,\n locale,\n settings.defaultLocale\n );\n if (extracted) {\n translations.push({\n content: extracted,\n fileName: file.fileName,\n fileFormat: file.transformFormat ?? file.fileFormat,\n dataFormat: file.dataFormat,\n locale,\n fileId: file.fileId,\n versionId: file.versionId,\n });\n }\n } else {\n // Non-composite: look for separate translation files\n const translatedFileName = fileMapping[locale]?.[file.fileName];\n if (translatedFileName && existsSync(translatedFileName)) {\n const translationFormat = file.transformFormat ?? file.fileFormat;\n let translatedContent: string;\n try {\n translatedContent = readFileContent(\n translatedFileName,\n translationFormat\n );\n } catch (error) {\n // One undecodable locale should not block the others: skip it and\n // report it in the summary.\n const relativePath = getRelative(translatedFileName);\n const reason = fileEncodingSkipReason(error);\n logger.warn(`Skipping ${relativePath}: ${reason}`);\n recordWarning('skipped_file', relativePath, reason);\n continue;\n }\n translations.push({\n content: translatedContent,\n fileName: translatedFileName,\n fileFormat: translationFormat,\n dataFormat: file.dataFormat,\n locale,\n fileId: file.fileId,\n versionId: file.versionId,\n });\n }\n }\n }\n return {\n source: sourceFile,\n translations,\n };\n });\n\n try {\n // Send all files in a single API call\n const { branchData } = await runUploadFilesWorkflow({\n files: uploadData,\n options: settings,\n });\n\n // Publish files to CDN if publish config exists\n await runPublishWorkflow(\n allFiles,\n publishMap,\n branchData.currentBranch.id,\n settings\n );\n } catch (error) {\n logErrorAndExit(`Error uploading files: ${error}`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BA,eAAsB,OACpB,UACe;AACf,KAAI,CAAC,SAAS,MACZ;CAGF,MAAM,oBAAoB,SAAS,WAAW,EAAE;CAChD,MAAM,EACJ,eAAe,WACf,kBACA,gBACA,qBACE,SAAS;CAIb,MAAM,EAAE,OAAO,UAAU,eAAe,MAAM,eAAe,SAAS;CACtE,MAAM,qCAAqB,IAAI,KAG5B;AAEH,KAAI,UAAU,MAAM;EAClB,MAAM,kBAAkB,IAAI,IAAI,SAAS,KAAK,SAAS,KAAK,SAAS,CAAC;AACtE,OAAK,MAAM,YAAY,UAAU,MAAM;GACrC,MAAM,eAAe,YAAY,SAAS;AAC1C,OAAI,CAAC,gBAAgB,IAAI,aAAa,CAAE;AAGxC,OADmB,mBAAmB,mBAAmB,SAC3C,EAAE,UACd,oBAAmB,IAAI,cAAc;IACnC;IACA,SAAS,SAAS,SAAS;IAC5B,CAAC;;;AAKR,KAAI,SAAS,WAAW,GAAG;AACzB,SAAO,MACL,yEACD;AACD;;AAGF,KAAI,CAAC,SAAS,cACZ,QAAO,gBAAgB,qBAAqB;AAE9C,KAAI,CAAC,oBAAoB,SAAS,CAAE,QAAO,SAAS,EAAE;CAEtD,MAAM,UAAU,SAAS,WAAW,EAAE;CAEtC,MAAM,cAAc,kBAClB,WACA,kBACA,gBACA,kBACA,SACA,SAAS,cACV;CAGD,MAAM,aAAa,SAAS,KAAK,SAAS;EACxC,MAAM,aAA2B,EAAE,GAAG,MAAM;EAE5C,MAAM,eAA+B,EAAE;EACvC,MAAM,gBAAgB,mBAAmB,IAAI,KAAK,SAAS;AAE3D,OAAK,MAAM,UAAU,QACnB,KAAI,eAAe;GAEjB,MAAM,YAAY,YAChB,cAAc,SACd,cAAc,UACd,mBACA,QACA,SAAS,cACV;AACD,OAAI,UACF,cAAa,KAAK;IAChB,SAAS;IACT,UAAU,KAAK;IACf,YAAY,KAAK,mBAAmB,KAAK;IACzC,YAAY,KAAK;IACjB;IACA,QAAQ,KAAK;IACb,WAAW,KAAK;IACjB,CAAC;SAEC;GAEL,MAAM,qBAAqB,YAAY,UAAU,KAAK;AACtD,OAAI,sBAAsB,WAAW,mBAAmB,EAAE;IACxD,MAAM,oBAAoB,KAAK,mBAAmB,KAAK;IACvD,IAAI;AACJ,QAAI;AACF,yBAAoB,gBAClB,oBACA,kBACD;aACM,OAAO;KAGd,MAAM,eAAe,YAAY,mBAAmB;KACpD,MAAM,SAAS,uBAAuB,MAAM;AAC5C,YAAO,KAAK,YAAY,aAAa,IAAI,SAAS;AAClD,mBAAc,gBAAgB,cAAc,OAAO;AACnD;;AAEF,iBAAa,KAAK;KAChB,SAAS;KACT,UAAU;KACV,YAAY;KACZ,YAAY,KAAK;KACjB;KACA,QAAQ,KAAK;KACb,WAAW,KAAK;KACjB,CAAC;;;AAIR,SAAO;GACL,QAAQ;GACR;GACD;GACD;AAEF,KAAI;EAEF,MAAM,EAAE,eAAe,MAAM,uBAAuB;GAClD,OAAO;GACP,SAAS;GACV,CAAC;AAGF,QAAM,mBACJ,UACA,YACA,WAAW,cAAc,IACzB,SACD;UACM,OAAO;AACd,kBAAgB,0BAA0B,QAAQ"}
1
+ {"version":3,"file":"upload.js","names":[],"sources":["../../../src/cli/commands/upload.ts"],"sourcesContent":["import {\n fileEncodingSkipReason,\n noDefaultLocaleError,\n} from '../../console/index.js';\nimport { exitSync, logErrorAndExit } from '../../console/logging.js';\nimport { logger } from '../../console/logger.js';\nimport { getRelative, readFile } from '../../fs/findFilepath.js';\nimport { readFileContent } from '../../fs/fileContent.js';\nimport { Settings } from '../../types/index.js';\nimport { UploadOptions } from '../base.js';\nimport { extractJson } from '../../formats/json/extractJson.js';\nimport { validateJsonSchema } from '../../formats/json/utils.js';\nimport { runUploadFilesWorkflow } from '../../workflows/upload.js';\nimport { existsSync } from 'node:fs';\nimport { createFileMapping } from '../../formats/files/fileMapping.js';\nimport type { FileToUpload } from 'generaltranslation/types';\nimport { hasValidCredentials } from './utils/validation.js';\nimport { runPublishWorkflow } from '../../workflows/publish.js';\nimport { aggregateFiles } from '../../formats/files/aggregateFiles.js';\nimport { recordWarning } from '../../state/translateWarnings.js';\nimport {\n parseXcstringsCatalog,\n serializeXcstringsSlice,\n sliceTranslationCatalog,\n type XcstringsCatalog,\n} from '../../formats/xcstrings/parseXcstrings.js';\nimport { gt } from '../../utils/gt.js';\n\n/**\n * Sends multiple files to the API for translation\n * @param settings - Translation options including API settings\n * @returns Promise that resolves when translation is complete\n */\nexport async function upload(\n settings: Settings & UploadOptions\n): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n const additionalOptions = settings.options || {};\n const {\n resolvedPaths: filePaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n } = settings.files;\n\n // Reuse the same source aggregation path as translate/stage so source\n // parsing behavior stays consistent across commands.\n const { files: allFiles, publishMap } = await aggregateFiles(settings);\n const sourceFileNames = new Set(allFiles.map((file) => file.fileName));\n const compositeJsonFiles = new Map<\n string,\n { filePath: string; content: string }\n >();\n\n if (filePaths.json) {\n for (const filePath of filePaths.json) {\n const relativePath = getRelative(filePath);\n if (!sourceFileNames.has(relativePath)) continue;\n\n const jsonSchema = validateJsonSchema(additionalOptions, filePath);\n if (jsonSchema?.composite) {\n compositeJsonFiles.set(relativePath, {\n filePath,\n content: readFile(filePath),\n });\n }\n }\n }\n\n // An .xcstrings catalog carries its own translations, so each locale's\n // upload is a slice of the same file rather than a separate translation\n // file. Catalogs aggregateFiles could not parse are already reported.\n const xcstringsCatalogs = new Map<string, XcstringsCatalog>();\n if (filePaths.xcstrings) {\n for (const filePath of filePaths.xcstrings) {\n const relativePath = getRelative(filePath);\n if (!sourceFileNames.has(relativePath)) continue;\n xcstringsCatalogs.set(\n relativePath,\n parseXcstringsCatalog(readFile(filePath))\n );\n }\n }\n\n if (allFiles.length === 0) {\n logger.error(\n 'No files to upload were found. Check your configuration and try again.'\n );\n return;\n }\n\n if (!settings.defaultLocale) {\n return logErrorAndExit(noDefaultLocaleError);\n }\n if (!hasValidCredentials(settings)) return exitSync(1);\n\n const locales = settings.locales || [];\n // Create file mapping for all file types\n const fileMapping = createFileMapping(\n filePaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n locales,\n settings.defaultLocale\n );\n\n // construct object\n const uploadData = allFiles.map((file) => {\n const sourceFile: FileToUpload = { ...file };\n\n const translations: FileToUpload[] = [];\n const compositeInfo = compositeJsonFiles.get(file.fileName);\n const xcstringsCatalog = xcstringsCatalogs.get(file.fileName);\n\n for (const locale of locales) {\n if (xcstringsCatalog) {\n // Catalog keys are canonical tags; the configured locale may be an alias.\n const slice = sliceTranslationCatalog(\n xcstringsCatalog,\n gt.resolveCanonicalLocale(locale)\n );\n // A locale the catalog does not carry has nothing to upload\n if (!slice) continue;\n translations.push({\n content: serializeXcstringsSlice(slice),\n fileName: file.fileName,\n fileFormat: file.transformFormat ?? file.fileFormat,\n dataFormat: file.dataFormat,\n locale,\n fileId: file.fileId,\n versionId: file.versionId,\n });\n } else if (compositeInfo) {\n // Composite JSON: extract translations from the same source file\n const extracted = extractJson(\n compositeInfo.content,\n compositeInfo.filePath,\n additionalOptions,\n locale,\n settings.defaultLocale\n );\n if (extracted) {\n translations.push({\n content: extracted,\n fileName: file.fileName,\n fileFormat: file.transformFormat ?? file.fileFormat,\n dataFormat: file.dataFormat,\n locale,\n fileId: file.fileId,\n versionId: file.versionId,\n });\n }\n } else {\n // Non-composite: look for separate translation files\n const translatedFileName = fileMapping[locale]?.[file.fileName];\n if (translatedFileName && existsSync(translatedFileName)) {\n const translationFormat = file.transformFormat ?? file.fileFormat;\n let translatedContent: string;\n try {\n translatedContent = readFileContent(\n translatedFileName,\n translationFormat\n );\n } catch (error) {\n // One undecodable locale should not block the others: skip it and\n // report it in the summary.\n const relativePath = getRelative(translatedFileName);\n const reason = fileEncodingSkipReason(error);\n logger.warn(`Skipping ${relativePath}: ${reason}`);\n recordWarning('skipped_file', relativePath, reason);\n continue;\n }\n translations.push({\n content: translatedContent,\n fileName: translatedFileName,\n fileFormat: translationFormat,\n dataFormat: file.dataFormat,\n locale,\n fileId: file.fileId,\n versionId: file.versionId,\n });\n }\n }\n }\n return {\n source: sourceFile,\n translations,\n };\n });\n\n try {\n // Send all files in a single API call\n const { branchData } = await runUploadFilesWorkflow({\n files: uploadData,\n options: settings,\n });\n\n // Publish files to CDN if publish config exists\n await runPublishWorkflow(\n allFiles,\n publishMap,\n branchData.currentBranch.id,\n settings\n );\n } catch (error) {\n logErrorAndExit(`Error uploading files: ${error}`);\n }\n}\n"],"mappings":"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"}
@@ -45,5 +45,9 @@ export declare const invalidConfigurationError = "The files configuration cannot
45
45
  export declare const lottieTranslateError = "Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\n 1. Stage the files for translation: npx gt stage\n 2. Fetch the finished translations: npx gt download\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.";
46
46
  export declare const branchResolutionError = "The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.";
47
47
  export declare const lottieExpressionsError: (files: string[]) => string;
48
+ export declare const xcstringsSourceLanguageMismatchError: (catalogs: {
49
+ file: string;
50
+ sourceLanguage: string;
51
+ }[], defaultLocale: string) => string;
48
52
  export declare const fileEncodingSkipReason: (error: unknown) => string;
49
53
  export declare const withOriginalError: (message: string, error: unknown) => string;
@@ -58,9 +58,10 @@ const invalidConfigurationError = `The files configuration cannot be used for th
58
58
  const lottieTranslateError = `Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\n 1. Stage the files for translation: npx gt stage\n 2. Fetch the finished translations: npx gt download\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.`;
59
59
  const branchResolutionError = `The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.`;
60
60
  const lottieExpressionsError = (files) => `The following Lottie file(s) use After Effects expressions, which contain executable code and are not supported yet:\n${files.map((file) => ` - ${file}`).join("\n")}\nRe-export the animation with expressions baked into keyframes (or removed), then try again.`;
61
+ const xcstringsSourceLanguageMismatchError = (catalogs, defaultLocale) => `The following .xcstrings catalog(s) declare a sourceLanguage that does not match the configured defaultLocale "${defaultLocale}":\n${catalogs.map(({ file, sourceLanguage }) => ` - ${file} (sourceLanguage "${sourceLanguage}")`).join("\n")}\nSet defaultLocale in gt.config.json to the catalog's sourceLanguage, or change the catalog's source language in Xcode, then try again.`;
61
62
  const fileEncodingSkipReason = (error) => `File could not be decoded: ${error instanceof Error ? error.message : String(error)}`;
62
63
  const withOriginalError = (message, error) => error != null ? `${message} Original error: ${String(error)}` : message;
63
64
  //#endregion
64
- export { branchResolutionError, devApiKeyError, fileEncodingSkipReason, invalidConfigurationError, lottieExpressionsError, lottieTranslateError, noApiKeyError, noDefaultLocaleError, noFilesError, noLocalesError, noProjectIdError, noSourceFileError, noVersionIdError, warnApiKeyInConfigSync, warnAsyncUseGT, warnAutoderiveNoResultsSync, warnDataAttrOnBranch, warnDeprecatedTSugarPropsSync, warnDeriveCircularSpreadSync, warnDeriveDestructuringSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, warnDeriveNonConstVariableSync, warnDeriveOptionalChainingSync, warnDeriveUnresolvableValueSync, warnDuplicateFunctionDefinitionSync, warnFailedToConstructJsxTreeSync, warnFunctionNotFoundSync, warnHasUnwrappedExpressionSync, warnInvalidDeclareVarNameSync, warnInvalidDeriveInitSync, warnInvalidFormatSync, warnInvalidIcuSync, warnInvalidMaxCharsSync, warnInvalidRequiresReviewSync, warnInvalidReturnSync, warnMissingReturnSync, warnNestedInternalTComponent, warnNestedTComponent, warnNonStaticExpressionSync, warnNonStringSync, warnRecursiveFunctionCallSync, warnSyncGetGT, warnTemplateLiteralSync, warnTernarySync, warnUnresolvedImportSync, warnVariablePropSync, withLocation, withOriginalError };
65
+ export { branchResolutionError, devApiKeyError, fileEncodingSkipReason, invalidConfigurationError, lottieExpressionsError, lottieTranslateError, noApiKeyError, noDefaultLocaleError, noFilesError, noLocalesError, noProjectIdError, noSourceFileError, noVersionIdError, warnApiKeyInConfigSync, warnAsyncUseGT, warnAutoderiveNoResultsSync, warnDataAttrOnBranch, warnDeprecatedTSugarPropsSync, warnDeriveCircularSpreadSync, warnDeriveDestructuringSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, warnDeriveNonConstVariableSync, warnDeriveOptionalChainingSync, warnDeriveUnresolvableValueSync, warnDuplicateFunctionDefinitionSync, warnFailedToConstructJsxTreeSync, warnFunctionNotFoundSync, warnHasUnwrappedExpressionSync, warnInvalidDeclareVarNameSync, warnInvalidDeriveInitSync, warnInvalidFormatSync, warnInvalidIcuSync, warnInvalidMaxCharsSync, warnInvalidRequiresReviewSync, warnInvalidReturnSync, warnMissingReturnSync, warnNestedInternalTComponent, warnNestedTComponent, warnNonStaticExpressionSync, warnNonStringSync, warnRecursiveFunctionCallSync, warnSyncGetGT, warnTemplateLiteralSync, warnTernarySync, warnUnresolvedImportSync, warnVariablePropSync, withLocation, withOriginalError, xcstringsSourceLanguageMismatchError };
65
66
 
66
67
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/console/index.ts"],"sourcesContent":["import { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { BRANCH_COMPONENT } from '../react/jsx/utils/constants.js';\nimport {\n colorizeFilepath,\n colorizeComponent,\n colorizeIdString,\n colorizeContent,\n colorizeLine,\n colorizeFunctionName,\n} from './colors.js';\nimport { formatCodeClamp } from './formatting.js';\n\nconst withWillErrorInNextVersion = (message: string): string =>\n `${message} (This will become an error in the next major version of the CLI.)`;\n\n// Derive function related errors\nconst withDeriveComponentError = (message: string): string =>\n `<Derive> rules violation: ${message}`;\n\nconst withDeriveFunctionError = (message: string): string =>\n `derive() rules violation: ${message}`;\n// Synchronous wrappers for backward compatibility\nexport const warnApiKeyInConfigSync = (optionsFilepath: string): string =>\n `${colorizeFilepath(\n optionsFilepath\n )}: Your API key is exposed! Remove it from the file and include it as an environment variable.`;\n\nexport const warnVariablePropSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component has dynamic attribute ${colorizeIdString(attrName)} with value: ${colorizeContent(\n value\n )}. Change ${colorizeIdString(attrName)} to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidReturnSync = (\n file: string,\n functionName: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Function ${colorizeFunctionName(functionName)} does not return a derivable (statically analyzable) expression. ${colorizeFunctionName(functionName)} must return either (1) a derivable string literal, (2) another derivable function invocation, (3) derivable JSX content, or (4) a ternary expression. Instead got:\\n${colorizeContent(expression)}`\n ),\n location\n );\n\n// TODO: this is temporary until we handle implicit returns\nexport const warnMissingReturnSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is wrapped in ${colorizeComponent('<Derive>')} tags but does not have an explicit return statement. Derivable functions must have an explicit return statement.`,\n location\n );\n\nexport const warnHasUnwrappedExpressionSync = (\n file: string,\n unwrappedExpressions: string[],\n id?: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component${\n id ? ` with id ${colorizeIdString(id)}` : ''\n } has children that could change at runtime. Use a variable component like ${colorizeComponent(\n '<Var>'\n )} to ensure this content is translated.\\n${colorizeContent(\n unwrappedExpressions.join('\\n')\n )}`,\n location\n );\n\nexport const warnFailedToConstructJsxTreeSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Failed to construct JsxTree! Call expression is not a valid createElement call: ${colorizeContent(code)}`,\n location\n );\n\nexport const warnNestedTComponent = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found nested <T> component. <T> components cannot be directly nested.`,\n location\n );\n\nexport const warnNestedInternalTComponent = (\n file: string,\n location?: string\n): string =>\n withLocation(\n file,\n `DEBUG: Found nested <GtInternalTranslateJsx> component. <GtInternalTranslateJsx> components cannot be directly nested.`,\n location\n );\n\nexport const warnNonStaticExpressionSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-static expression for attribute ${colorizeIdString(\n attrName\n )}: ${colorizeContent(value)}. Change \"${colorizeIdString(attrName)}\" to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidMaxCharsSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid maxChars value: ${colorizeContent(value)}. maxChars must be a numeric literal, e.g. maxChars={10}, to ensure this content is translated.`,\n location\n );\n\nexport const warnDeprecatedTSugarPropsSync = (locations: string[]): string =>\n createDiagnosticMessage({\n whatHappened: `Found ${locations.length} deprecated ${colorizeIdString(\n '$'\n )}-prefixed prop${locations.length === 1 ? '' : 's'} on ${colorizeComponent(\n '<T>'\n )} components`,\n fix: `Use the unprefixed forms instead (${colorizeIdString(\n 'context'\n )}, ${colorizeIdString('id')}, ${colorizeIdString('maxChars')}, ${colorizeIdString(\n 'requiresReview'\n )}); support for the ${colorizeIdString('$')}-prefixed forms will be removed in the next major version`,\n }) +\n '\\n' +\n locations.map((location) => ` ${colorizeLine(location)}`).join('\\n');\n\nexport const warnInvalidFormatSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid $format value: ${colorizeContent(value)}. Must be one of: 'ICU', 'STRING', 'I18NEXT'.`,\n location\n );\n\nexport const warnInvalidRequiresReviewSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid requiresReview value: ${colorizeContent(value)}. Must be a boolean literal (true or false) — strings and dynamic expressions are not allowed.`,\n location\n );\n\nexport const warnInvalidIcuSync = (\n file: string,\n value: string,\n error: string,\n location?: string\n): string =>\n withWillErrorInNextVersion(\n withLocation(\n file,\n `Found invalid ICU string: ${colorizeContent(value)}. Change the value to a valid ICU to ensure this content is translated. Error message: ${error}.`,\n location\n )\n );\n\nexport const warnTemplateLiteralSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found template literal with quasis (${colorizeContent(value)}). Change the template literal to a string to ensure this content is translated.`,\n location\n );\n\nexport const warnNonStringSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-string literal (${colorizeContent(value)}). Change the value to a string literal to ensure this content is translated.`,\n location\n );\n\nexport const warnAsyncUseGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found useGT() in an async function. Use getGT() instead, or make the function synchronous.`,\n location\n );\n\nexport const warnSyncGetGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found getGT() in a synchronous function. Use useGT() instead, or make the function async.`,\n location\n );\n\nexport const warnTernarySync = (file: string, location?: string): string =>\n withLocation(\n file,\n 'Found ternary expression. A Branch component may be more appropriate here.',\n location\n );\n\nexport const withLocation = (\n file: string,\n message: string,\n location?: string\n): string =>\n `${colorizeFilepath(file)}${location ? ` (${colorizeLine(location)})` : ''}: ${message}`;\n\nexport const warnFunctionNotFoundSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} definition could not be resolved. This might affect translation resolution for this ${colorizeComponent('<T>')} component.`,\n location\n );\n\nexport const warnInvalidDeclareVarNameSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid declareVar() $name tag. Must be a derivable (statically analyzable) expression. Received: ${colorizeContent(value)}.`,\n location\n );\n\nexport const warnDuplicateFunctionDefinitionSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is defined multiple times. Only the first definition will be used.`,\n location\n );\n\nexport const warnInvalidDeriveInitSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `The definition for ${colorizeFunctionName(functionName)} could not be resolved. When using arrow syntax to define a derivable (statically analyzable) function, the right hand side or the assignment MUST only contain the arrow function itself and no other expressions.\nExample: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = () => { ... }`)}\nInvalid: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = [() => { ... }][0]`)}`\n ),\n location\n );\n\nexport const warnDataAttrOnBranch = (\n file: string,\n attrName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent(`<${BRANCH_COMPONENT}>`)} component ignores attributes prefixed with ${colorizeIdString('\"data-\"')}. Found ${colorizeIdString(attrName)}. Remove it or use a different attribute name.`,\n location\n );\n\nexport const warnRecursiveFunctionCallSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Recursive function call detected: ${colorizeFunctionName(functionName)}. A derivable (statically analyzable) function cannot use recursive calls to construct its result.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNotWrappedSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. This call is not wrapped in derive(). Ensure the function is properly wrapped with derive() and does not have circular import dependencies.`\n ),\n location\n );\n\nexport const warnDeriveNonConstVariableSync = (\n file: string,\n varName: string,\n kind: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} is declared with '${kind}' but only 'const' declarations can be resolved statically. Change it to 'const'.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNoResultsSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. derive() can only receive function invocations and cannot use undefined values or looped calls to construct its result.`\n ),\n location\n );\n\nexport const warnAutoderiveNoResultsSync = (\n file: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Autoderive could not resolve ${colorizeFunctionName(formatCodeClamp(expression))}. Only function calls with statically determinable return values can be used directly in t(). Consider wrapping with derive() for explicit derivation, or use an interpolation variable instead.`,\n location\n );\n\nexport const warnDeriveUnresolvableValueSync = (\n file: string,\n key: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Object property ${colorizeFunctionName(formatCodeClamp(key))} could not be resolved to a static string value. Only string literals, template literals, conditionals, and function calls returning strings are supported.`\n ),\n location\n );\n\nexport const warnDeriveCircularSpreadSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Circular spread detected involving ${colorizeFunctionName(varName)}. Spread references that form a cycle cannot be resolved statically.`\n ),\n location\n );\n\nexport const warnDeriveDestructuringSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} uses destructuring syntax, which is not yet supported in derive(). Assign the value to a const variable directly instead.`\n ),\n location\n );\n\nexport const warnDeriveOptionalChainingSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Optional chaining (${colorizeFunctionName(formatCodeClamp(code))}) is not supported in derive(). Optional chaining implies the value could be undefined, which cannot be resolved statically. Use a non-optional access instead.`\n ),\n location\n );\n\nexport const warnUnresolvedImportSync = (\n file: string,\n functionName: string,\n importPath: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Could not resolve import ${colorizeFunctionName(importPath)} for function ${colorizeFunctionName(functionName)}. Translation strings inside this function will not be extracted.`,\n location\n );\n\n// Re-export error messages\nexport const noLocalesError = `No target locales were found. Add locales to gt.config.json or pass them with the --locales flag.`;\nexport const noDefaultLocaleError = `No default locale was found. Add defaultLocale to gt.config.json or pass it with --default-locale.`;\nexport const noFilesError = `The files configuration is missing or invalid. Check the files section in gt.config.json and try again.`;\nexport const noSourceFileError = `No source translation file was found. Check your translations directory and default locale configuration.`;\nexport const noApiKeyError = `No API key was found. Pass --api-key or set the GT_API_KEY environment variable.`;\nexport const devApiKeyError = `Development API keys cannot be used with the General Translation API. Use a production API key instead.\\nGenerate a production API key with: npx gt auth -t production`;\nexport const noProjectIdError = `No project ID was found. Pass --project-id, add projectId to gt.config.json, or set the GT_PROJECT_ID environment variable.`;\nexport const noVersionIdError = `No version ID was found. Pass --version-id or add _versionId to gt.config.json.`;\nexport const invalidConfigurationError = `The files configuration cannot be used for this operation. Provide a valid download configuration or set --publish true to upload translations to the CDN.`;\nexport const lottieTranslateError = `Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\\n 1. Stage the files for translation: npx gt stage\\n 2. Fetch the finished translations: npx gt download\\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.`;\nexport const branchResolutionError = `The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.`;\n\nexport const lottieExpressionsError = (files: string[]): string =>\n `The following Lottie file(s) use After Effects expressions, which contain executable code and are not supported yet:\\n${files\n .map((file) => ` - ${file}`)\n .join(\n '\\n'\n )}\\nRe-export the animation with expressions baked into keyframes (or removed), then try again.`;\n\nexport const fileEncodingSkipReason = (error: unknown): string =>\n `File could not be decoded: ${error instanceof Error ? error.message : String(error)}`;\n\nexport const withOriginalError = (message: string, error: unknown): string =>\n error != null ? `${message} Original error: ${String(error)}` : message;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/console/index.ts"],"sourcesContent":["import { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { BRANCH_COMPONENT } from '../react/jsx/utils/constants.js';\nimport {\n colorizeFilepath,\n colorizeComponent,\n colorizeIdString,\n colorizeContent,\n colorizeLine,\n colorizeFunctionName,\n} from './colors.js';\nimport { formatCodeClamp } from './formatting.js';\n\nconst withWillErrorInNextVersion = (message: string): string =>\n `${message} (This will become an error in the next major version of the CLI.)`;\n\n// Derive function related errors\nconst withDeriveComponentError = (message: string): string =>\n `<Derive> rules violation: ${message}`;\n\nconst withDeriveFunctionError = (message: string): string =>\n `derive() rules violation: ${message}`;\n// Synchronous wrappers for backward compatibility\nexport const warnApiKeyInConfigSync = (optionsFilepath: string): string =>\n `${colorizeFilepath(\n optionsFilepath\n )}: Your API key is exposed! Remove it from the file and include it as an environment variable.`;\n\nexport const warnVariablePropSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component has dynamic attribute ${colorizeIdString(attrName)} with value: ${colorizeContent(\n value\n )}. Change ${colorizeIdString(attrName)} to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidReturnSync = (\n file: string,\n functionName: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Function ${colorizeFunctionName(functionName)} does not return a derivable (statically analyzable) expression. ${colorizeFunctionName(functionName)} must return either (1) a derivable string literal, (2) another derivable function invocation, (3) derivable JSX content, or (4) a ternary expression. Instead got:\\n${colorizeContent(expression)}`\n ),\n location\n );\n\n// TODO: this is temporary until we handle implicit returns\nexport const warnMissingReturnSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is wrapped in ${colorizeComponent('<Derive>')} tags but does not have an explicit return statement. Derivable functions must have an explicit return statement.`,\n location\n );\n\nexport const warnHasUnwrappedExpressionSync = (\n file: string,\n unwrappedExpressions: string[],\n id?: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent('<T>')} component${\n id ? ` with id ${colorizeIdString(id)}` : ''\n } has children that could change at runtime. Use a variable component like ${colorizeComponent(\n '<Var>'\n )} to ensure this content is translated.\\n${colorizeContent(\n unwrappedExpressions.join('\\n')\n )}`,\n location\n );\n\nexport const warnFailedToConstructJsxTreeSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Failed to construct JsxTree! Call expression is not a valid createElement call: ${colorizeContent(code)}`,\n location\n );\n\nexport const warnNestedTComponent = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found nested <T> component. <T> components cannot be directly nested.`,\n location\n );\n\nexport const warnNestedInternalTComponent = (\n file: string,\n location?: string\n): string =>\n withLocation(\n file,\n `DEBUG: Found nested <GtInternalTranslateJsx> component. <GtInternalTranslateJsx> components cannot be directly nested.`,\n location\n );\n\nexport const warnNonStaticExpressionSync = (\n file: string,\n attrName: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-static expression for attribute ${colorizeIdString(\n attrName\n )}: ${colorizeContent(value)}. Change \"${colorizeIdString(attrName)}\" to ensure this content is translated.`,\n location\n );\n\nexport const warnInvalidMaxCharsSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid maxChars value: ${colorizeContent(value)}. maxChars must be a numeric literal, e.g. maxChars={10}, to ensure this content is translated.`,\n location\n );\n\nexport const warnDeprecatedTSugarPropsSync = (locations: string[]): string =>\n createDiagnosticMessage({\n whatHappened: `Found ${locations.length} deprecated ${colorizeIdString(\n '$'\n )}-prefixed prop${locations.length === 1 ? '' : 's'} on ${colorizeComponent(\n '<T>'\n )} components`,\n fix: `Use the unprefixed forms instead (${colorizeIdString(\n 'context'\n )}, ${colorizeIdString('id')}, ${colorizeIdString('maxChars')}, ${colorizeIdString(\n 'requiresReview'\n )}); support for the ${colorizeIdString('$')}-prefixed forms will be removed in the next major version`,\n }) +\n '\\n' +\n locations.map((location) => ` ${colorizeLine(location)}`).join('\\n');\n\nexport const warnInvalidFormatSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid $format value: ${colorizeContent(value)}. Must be one of: 'ICU', 'STRING', 'I18NEXT'.`,\n location\n );\n\nexport const warnInvalidRequiresReviewSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid requiresReview value: ${colorizeContent(value)}. Must be a boolean literal (true or false) — strings and dynamic expressions are not allowed.`,\n location\n );\n\nexport const warnInvalidIcuSync = (\n file: string,\n value: string,\n error: string,\n location?: string\n): string =>\n withWillErrorInNextVersion(\n withLocation(\n file,\n `Found invalid ICU string: ${colorizeContent(value)}. Change the value to a valid ICU to ensure this content is translated. Error message: ${error}.`,\n location\n )\n );\n\nexport const warnTemplateLiteralSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found template literal with quasis (${colorizeContent(value)}). Change the template literal to a string to ensure this content is translated.`,\n location\n );\n\nexport const warnNonStringSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found non-string literal (${colorizeContent(value)}). Change the value to a string literal to ensure this content is translated.`,\n location\n );\n\nexport const warnAsyncUseGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found useGT() in an async function. Use getGT() instead, or make the function synchronous.`,\n location\n );\n\nexport const warnSyncGetGT = (file: string, location?: string): string =>\n withLocation(\n file,\n `Found getGT() in a synchronous function. Use useGT() instead, or make the function async.`,\n location\n );\n\nexport const warnTernarySync = (file: string, location?: string): string =>\n withLocation(\n file,\n 'Found ternary expression. A Branch component may be more appropriate here.',\n location\n );\n\nexport const withLocation = (\n file: string,\n message: string,\n location?: string\n): string =>\n `${colorizeFilepath(file)}${location ? ` (${colorizeLine(location)})` : ''}: ${message}`;\n\nexport const warnFunctionNotFoundSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} definition could not be resolved. This might affect translation resolution for this ${colorizeComponent('<T>')} component.`,\n location\n );\n\nexport const warnInvalidDeclareVarNameSync = (\n file: string,\n value: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Found invalid declareVar() $name tag. Must be a derivable (statically analyzable) expression. Received: ${colorizeContent(value)}.`,\n location\n );\n\nexport const warnDuplicateFunctionDefinitionSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Function ${colorizeFunctionName(functionName)} is defined multiple times. Only the first definition will be used.`,\n location\n );\n\nexport const warnInvalidDeriveInitSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `The definition for ${colorizeFunctionName(functionName)} could not be resolved. When using arrow syntax to define a derivable (statically analyzable) function, the right hand side or the assignment MUST only contain the arrow function itself and no other expressions.\nExample: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = () => { ... }`)}\nInvalid: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = [() => { ... }][0]`)}`\n ),\n location\n );\n\nexport const warnDataAttrOnBranch = (\n file: string,\n attrName: string,\n location?: string\n): string =>\n withLocation(\n file,\n `${colorizeComponent(`<${BRANCH_COMPONENT}>`)} component ignores attributes prefixed with ${colorizeIdString('\"data-\"')}. Found ${colorizeIdString(attrName)}. Remove it or use a different attribute name.`,\n location\n );\n\nexport const warnRecursiveFunctionCallSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveComponentError(\n `Recursive function call detected: ${colorizeFunctionName(functionName)}. A derivable (statically analyzable) function cannot use recursive calls to construct its result.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNotWrappedSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. This call is not wrapped in derive(). Ensure the function is properly wrapped with derive() and does not have circular import dependencies.`\n ),\n location\n );\n\nexport const warnDeriveNonConstVariableSync = (\n file: string,\n varName: string,\n kind: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} is declared with '${kind}' but only 'const' declarations can be resolved statically. Change it to 'const'.`\n ),\n location\n );\n\nexport const warnDeriveFunctionNoResultsSync = (\n file: string,\n functionName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. derive() can only receive function invocations and cannot use undefined values or looped calls to construct its result.`\n ),\n location\n );\n\nexport const warnAutoderiveNoResultsSync = (\n file: string,\n expression: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Autoderive could not resolve ${colorizeFunctionName(formatCodeClamp(expression))}. Only function calls with statically determinable return values can be used directly in t(). Consider wrapping with derive() for explicit derivation, or use an interpolation variable instead.`,\n location\n );\n\nexport const warnDeriveUnresolvableValueSync = (\n file: string,\n key: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Object property ${colorizeFunctionName(formatCodeClamp(key))} could not be resolved to a static string value. Only string literals, template literals, conditionals, and function calls returning strings are supported.`\n ),\n location\n );\n\nexport const warnDeriveCircularSpreadSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Circular spread detected involving ${colorizeFunctionName(varName)}. Spread references that form a cycle cannot be resolved statically.`\n ),\n location\n );\n\nexport const warnDeriveDestructuringSync = (\n file: string,\n varName: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Variable ${colorizeFunctionName(varName)} uses destructuring syntax, which is not yet supported in derive(). Assign the value to a const variable directly instead.`\n ),\n location\n );\n\nexport const warnDeriveOptionalChainingSync = (\n file: string,\n code: string,\n location?: string\n): string =>\n withLocation(\n file,\n withDeriveFunctionError(\n `Optional chaining (${colorizeFunctionName(formatCodeClamp(code))}) is not supported in derive(). Optional chaining implies the value could be undefined, which cannot be resolved statically. Use a non-optional access instead.`\n ),\n location\n );\n\nexport const warnUnresolvedImportSync = (\n file: string,\n functionName: string,\n importPath: string,\n location?: string\n): string =>\n withLocation(\n file,\n `Could not resolve import ${colorizeFunctionName(importPath)} for function ${colorizeFunctionName(functionName)}. Translation strings inside this function will not be extracted.`,\n location\n );\n\n// Re-export error messages\nexport const noLocalesError = `No target locales were found. Add locales to gt.config.json or pass them with the --locales flag.`;\nexport const noDefaultLocaleError = `No default locale was found. Add defaultLocale to gt.config.json or pass it with --default-locale.`;\nexport const noFilesError = `The files configuration is missing or invalid. Check the files section in gt.config.json and try again.`;\nexport const noSourceFileError = `No source translation file was found. Check your translations directory and default locale configuration.`;\nexport const noApiKeyError = `No API key was found. Pass --api-key or set the GT_API_KEY environment variable.`;\nexport const devApiKeyError = `Development API keys cannot be used with the General Translation API. Use a production API key instead.\\nGenerate a production API key with: npx gt auth -t production`;\nexport const noProjectIdError = `No project ID was found. Pass --project-id, add projectId to gt.config.json, or set the GT_PROJECT_ID environment variable.`;\nexport const noVersionIdError = `No version ID was found. Pass --version-id or add _versionId to gt.config.json.`;\nexport const invalidConfigurationError = `The files configuration cannot be used for this operation. Provide a valid download configuration or set --publish true to upload translations to the CDN.`;\nexport const lottieTranslateError = `Lottie translations are processed asynchronously, so the translate command cannot complete them in one run. Use the stage and download flow instead:\\n 1. Stage the files for translation: npx gt stage\\n 2. Fetch the finished translations: npx gt download\\nTranslations that are still processing are skipped, so re-run npx gt download until all of them have been downloaded.`;\nexport const branchResolutionError = `The current git branch could not be resolved. Specify a branch explicitly or run the command from a git worktree with branch metadata available.`;\n\nexport const lottieExpressionsError = (files: string[]): string =>\n `The following Lottie file(s) use After Effects expressions, which contain executable code and are not supported yet:\\n${files\n .map((file) => ` - ${file}`)\n .join(\n '\\n'\n )}\\nRe-export the animation with expressions baked into keyframes (or removed), then try again.`;\n\nexport const xcstringsSourceLanguageMismatchError = (\n catalogs: { file: string; sourceLanguage: string }[],\n defaultLocale: string\n): string =>\n `The following .xcstrings catalog(s) declare a sourceLanguage that does not match the configured defaultLocale \"${defaultLocale}\":\\n${catalogs\n .map(\n ({ file, sourceLanguage }) =>\n ` - ${file} (sourceLanguage \"${sourceLanguage}\")`\n )\n .join(\n '\\n'\n )}\\nSet defaultLocale in gt.config.json to the catalog's sourceLanguage, or change the catalog's source language in Xcode, then try again.`;\n\nexport const fileEncodingSkipReason = (error: unknown): string =>\n `File could not be decoded: ${error instanceof Error ? error.message : String(error)}`;\n\nexport const withOriginalError = (message: string, error: unknown): string =>\n error != null ? `${message} Original error: ${String(error)}` : message;\n"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import { logger } from "../../console/logger.js";
2
2
  import { hashStringSync, hashVersionId } from "../../utils/hash.js";
3
+ import { gt } from "../../utils/gt.js";
3
4
  import { logErrorAndExit } from "../../console/logging.js";
4
5
  import { getRelative, readBinaryFileBase64, readFile } from "../../fs/findFilepath.js";
5
- import { fileEncodingSkipReason, lottieExpressionsError } from "../../console/index.js";
6
+ import { fileEncodingSkipReason, lottieExpressionsError, xcstringsSourceLanguageMismatchError } from "../../console/index.js";
6
7
  import { SUPPORTED_FILE_EXTENSIONS } from "./supportedFiles.js";
7
8
  import { getTransformFormatProperty } from "./transformFormat.js";
8
9
  import { determineLibrary } from "../../fs/determineFramework/index.js";
@@ -12,6 +13,7 @@ import { recordWarning } from "../../state/translateWarnings.js";
12
13
  import { buildPublishMap } from "../../utils/resolvePublish.js";
13
14
  import { lottieHasExpressions } from "./detectLottieExpressions.js";
14
15
  import { parseJson } from "../json/parseJson.js";
16
+ import { parseXcstringsCatalog, serializeXcstringsSlice, sliceSourceCatalog } from "../xcstrings/parseXcstrings.js";
15
17
  import { resolveMintlifyRefs, shouldResolveRefs } from "../../utils/resolveMintlifyRefs.js";
16
18
  import { storeRefMap } from "../../state/mintlifyRefMap.js";
17
19
  import { validateYamlSchema } from "../yaml/utils.js";
@@ -245,8 +247,43 @@ async function aggregateFiles(settings) {
245
247
  });
246
248
  files.push(...verbatimFiles.filter((file) => file !== null));
247
249
  }
250
+ if (filePaths.xcstrings) {
251
+ const sourceLanguageMismatches = [];
252
+ const xcstringsFiles = filePaths.xcstrings.map((filePath) => {
253
+ const content = readFile(filePath);
254
+ const relativePath = getRelative(filePath);
255
+ let catalog;
256
+ try {
257
+ catalog = parseXcstringsCatalog(content);
258
+ } catch (error) {
259
+ const reason = error instanceof Error ? error.message : "xcstrings file is not parsable";
260
+ logger.warn(`Skipping ${relativePath}: ${reason}`);
261
+ recordWarning("skipped_file", relativePath, reason);
262
+ return null;
263
+ }
264
+ if (gt.resolveCanonicalLocale(catalog.sourceLanguage) !== gt.resolveCanonicalLocale(settings.defaultLocale)) {
265
+ sourceLanguageMismatches.push({
266
+ file: relativePath,
267
+ sourceLanguage: catalog.sourceLanguage
268
+ });
269
+ return null;
270
+ }
271
+ const sourceSlice = serializeXcstringsSlice(sliceSourceCatalog(catalog));
272
+ return {
273
+ content: sourceSlice,
274
+ fileName: relativePath,
275
+ fileFormat: "XCSTRINGS",
276
+ ...getTransformFormatProperty(settings, "xcstrings"),
277
+ fileId: hashStringSync(relativePath),
278
+ versionId: hashVersionId(sourceSlice, requiresReviewPaths.has(filePath)),
279
+ locale: settings.defaultLocale
280
+ };
281
+ }).filter((file) => file !== null);
282
+ if (sourceLanguageMismatches.length > 0) logErrorAndExit(xcstringsSourceLanguageMismatchError(sourceLanguageMismatches, settings.defaultLocale));
283
+ files.push(...xcstringsFiles);
284
+ }
248
285
  for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
249
- if (fileType === "json" || fileType === "yaml" || fileType === "twilioContentJson" || fileType === "lottie" || fileType === "dotStrings" || fileType === "dotStringsdict" || fileType === "androidStrings") continue;
286
+ if (fileType === "json" || fileType === "yaml" || fileType === "twilioContentJson" || fileType === "lottie" || fileType === "dotStrings" || fileType === "dotStringsdict" || fileType === "androidStrings" || fileType === "xcstrings") continue;
250
287
  if (filePaths[fileType]) {
251
288
  const parsed = filePaths[fileType].map((filePath) => {
252
289
  const content = readFile(filePath);