UNPKG

i18n-ai-translate

Version:

AI-powered localization CLI, Node library, and GitHub Action. Translate i18next JSON, Gettext PO, Java .properties, and iOS .strings with ChatGPT, Claude, Gemini, or local Ollama models.

110 lines (98 loc) 3.69 kB
import { DEFAULT_BATCH_SIZE, DEFAULT_REQUEST_TOKENS, DEFAULT_TEMPLATED_STRING_PREFIX, DEFAULT_TEMPLATED_STRING_SUFFIX, FLATTEN_DELIMITER, } from "./constants"; import { flatten } from "flat"; import { isValidLanguageCode, printInfo, resolveLanguageCode } from "./utils"; import ChatPool from "./chat_pool"; import GenerateTranslationJSON from "./generate_json/generate"; import RateLimiter from "./rate_limiter"; import type CheckOptions from "./interfaces/check_options"; import type { CheckReport } from "./interfaces/check_options"; function setDefaults(options: CheckOptions): void { if (!options.templatedStringPrefix) options.templatedStringPrefix = DEFAULT_TEMPLATED_STRING_PREFIX; if (!options.templatedStringSuffix) options.templatedStringSuffix = DEFAULT_TEMPLATED_STRING_SUFFIX; if (!options.batchMaxTokens) options.batchMaxTokens = DEFAULT_REQUEST_TOKENS; if (!options.batchSize) options.batchSize = DEFAULT_BATCH_SIZE; if (!options.verbose) options.verbose = false; if (options.continueOnError === undefined) options.continueOnError = true; } /** * Validate an already-translated target file against its source by * running the verification pipeline without the preceding translation * step. Returns a report listing every key the model flagged as * incorrect, along with a suggested correction where available. * * No files are written. */ export async function check(options: CheckOptions): Promise<CheckReport> { setDefaults(options); options.inputLanguageCode = resolveLanguageCode(options.inputLanguageCode); options.outputLanguageCode = resolveLanguageCode( options.outputLanguageCode, ); if (!isValidLanguageCode(options.inputLanguageCode)) { throw new Error( `Invalid input language code: ${options.inputLanguageCode}`, ); } if (!isValidLanguageCode(options.outputLanguageCode)) { throw new Error( `Invalid output language code: ${options.outputLanguageCode}`, ); } // Reuse caller-supplied pool/limiter when provided; see the // symmetric comment in translate.ts::getPool. const pool = options.pool ?? ChatPool.create({ apiKey: options.apiKey, chatParams: options.chatParams, concurrency: Math.max(1, options.concurrency ?? 1), engine: options.engine, host: options.host, model: options.model, rateLimiter: options.rateLimiter ?? new RateLimiter( options.rateLimitMs, options.verbose as boolean, options.tokensPerMinute, ), }); const flatSource = flatten(options.inputJSON, { delimiter: FLATTEN_DELIMITER, }) as { [key: string]: string }; const flatTarget = flatten(options.targetJSON, { delimiter: FLATTEN_DELIMITER, }) as { [key: string]: string }; if (options.verbose) { printInfo( `Checking ${Object.keys(flatTarget).length} target keys against source...\n`, ); } const generator = new GenerateTranslationJSON(options); const rawIssues = await generator.checkJSON({ flatSource, flatTarget, options, pool, }); return { issues: rawIssues.map((i) => ({ issue: i.issue, key: i.key, original: i.original, suggestion: i.suggestion, translated: i.translated, })), languageCode: options.outputLanguageCode, totalKeys: Object.keys(flatTarget).length, }; }