UNPKG

i18n-ai-translate

Version:

Use LLMs to translate your i18n JSON to any language.

196 lines (187 loc) 7.67 kB
import { CLI_HELP, DEFAULT_TEMPLATED_STRING_PREFIX, DEFAULT_TEMPLATED_STRING_SUFFIX, } from "./constants"; import { Command } from "commander"; import { printError } from "./utils"; import { processModelArgs, processOverridePromptFile } from "./cli_helpers"; import { translateDirectoryDiff } from "./translate_directory"; import { translateFileDiff } from "./translate_file"; import fs, { mkdtempSync } from "fs"; import path from "path"; import type DryRun from "./interfaces/dry_run"; import type OverridePrompt from "./interfaces/override_prompt"; /** * Builds the diff command for comparing i18n files or directories. * @returns the diff command with its options and action. */ export default function buildDiffCommand(): Command { return new Command("diff") .requiredOption( "-b, --before <fileOrDirectoryBefore>", "Source i18n file or directory before changes, in the jsons/ directory if a relative path is given", ) .requiredOption( "-a, --after <fileOrDirectoryAfter>", "Source i18n file or directory after changes, in the jsons/ directory if a relative path is given", ) .requiredOption( "-l, --input-language <inputLanguageCode>", "The input language's code, in ISO6391 (e.g. en, fr)", ) .requiredOption("-e, --engine <engine>", CLI_HELP.Engine) .option("-m, --model <model>", CLI_HELP.Model) .option("-r, --rate-limit-ms <rateLimitMs>", CLI_HELP.RateLimit) .option("-k, --api-key <API key>", "API key") .option("-h, --host <hostIP:port>", CLI_HELP.OllamaHost) .option( "--ensure-changed-translation", CLI_HELP.EnsureChangedTranslation, false, ) .option( "-p, --templated-string-prefix <prefix>", "Prefix for templated strings", DEFAULT_TEMPLATED_STRING_PREFIX, ) .option( "-s, --templated-string-suffix <suffix>", "Suffix for templated strings", DEFAULT_TEMPLATED_STRING_SUFFIX, ) .option("-n, --batch-size <batchSize>", CLI_HELP.BatchSize) .option( "--skip-translation-verification", CLI_HELP.SkipTranslationVerification, false, ) .option( "--skip-styling-verification", CLI_HELP.SkipStylingVerification, false, ) .option( "--override-prompt <path to JSON file>", CLI_HELP.OverridePromptFile, ) .option("--verbose", CLI_HELP.Verbose, false) .option("--prompt-mode <prompt-mode>", CLI_HELP.PromptMode) .option("--batch-max-tokens <batch-max-tokens>", CLI_HELP.MaxTokens) .option("--dry-run", CLI_HELP.DryRun, false) .action(async (options: any) => { const { model, chatParams, rateLimitMs, apiKey, host, promptMode, batchSize, batchMaxTokens, } = processModelArgs(options); let overridePrompt: OverridePrompt | undefined; if (options.overridePrompt) { overridePrompt = processOverridePromptFile( options.overridePrompt, ); } let dryRun: DryRun | undefined; if (options.dryRun) { dryRun = { basePath: mkdtempSync( `/tmp/i18n-ai-translate-${new Date().toISOString().replace(/[:.]/g, "-")}-`, ), }; } const jsonFolder = path.resolve(process.cwd(), "jsons"); let beforeInputPath: string; if (path.isAbsolute(options.before)) { beforeInputPath = path.resolve(options.before); } else { beforeInputPath = path.resolve(jsonFolder, options.before); if (!fs.existsSync(beforeInputPath)) { beforeInputPath = path.resolve( process.cwd(), options.before, ); } } let afterInputPath: string; if (path.isAbsolute(options.after)) { afterInputPath = path.resolve(options.after); } else { afterInputPath = path.resolve(jsonFolder, options.after); if (!fs.existsSync(afterInputPath)) { afterInputPath = path.resolve(process.cwd(), options.after); } } if ( fs.statSync(beforeInputPath).isFile() !== fs.statSync(afterInputPath).isFile() ) { printError( "--before and --after arguments must be both files or both directories", ); return; } if (fs.statSync(beforeInputPath).isFile()) { // Ensure they're in the same path if ( path.dirname(beforeInputPath) !== path.dirname(afterInputPath) ) { printError("Input files are not in the same directory"); return; } await translateFileDiff({ apiKey, batchMaxTokens, batchSize, chatParams, dryRun, engine: options.engine, ensureChangedTranslation: options.ensureChangedTranslation, host, inputAfterFileOrPath: afterInputPath, inputBeforeFileOrPath: beforeInputPath, inputLanguageCode: options.inputLanguage, model, overridePrompt, promptMode, rateLimitMs, skipStylingVerification: options.skipStylingVerification, skipTranslationVerification: options.skipTranslationVerification, templatedStringPrefix: options.templatedStringPrefix, templatedStringSuffix: options.templatedStringSuffix, verbose: options.verbose, }); } else { await translateDirectoryDiff({ apiKey, baseDirectory: path.resolve(beforeInputPath, ".."), batchMaxTokens: options.batchMaxTokens, batchSize: options.batchSize, chatParams, dryRun, engine: options.engine, ensureChangedTranslation: options.ensureChangedTranslation, host, inputFolderNameAfter: afterInputPath, inputFolderNameBefore: beforeInputPath, inputLanguageCode: options.inputLanguage, model, overridePrompt, promptMode, rateLimitMs, skipStylingVerification: options.skipStylingVerification, skipTranslationVerification: options.skipTranslationVerification, templatedStringPrefix: options.templatedStringPrefix, templatedStringSuffix: options.templatedStringSuffix, verbose: options.verbose, }); } }); }