i18n-ai-translate
Version:
Use LLMs to translate your i18n JSON to any language.
309 lines • 15.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = buildTranslateCommand;
const constants_1 = require("./constants");
const commander_1 = require("commander");
const utils_1 = require("./utils");
const cli_helpers_1 = require("./cli_helpers");
const translate_directory_1 = require("./translate_directory");
const translate_file_1 = require("./translate_file");
const fs_1 = __importStar(require("fs"));
const path_1 = __importDefault(require("path"));
/**
* Builds the translate command for translating i18n files or directories.
* @returns the translate command with its options and action.
*/
function buildTranslateCommand() {
return new commander_1.Command("translate")
.requiredOption("-i, --input <input>", "Source i18n file or path of source language, in the jsons/ directory if a relative path is given")
.option("-o, --output-languages [language codes...]", "A list of languages to translate to")
.requiredOption("-e, --engine <engine>", constants_1.CLI_HELP.Engine)
.option("-m, --model <model>", constants_1.CLI_HELP.Model)
.option("-r, --rate-limit-ms <rateLimitMs>", constants_1.CLI_HELP.RateLimit)
.option("-f, --force-language-name <language name>", "Force output language name")
.option("-A, --all-languages", "Translate to all supported languages")
.option("-p, --templated-string-prefix <prefix>", "Prefix for templated strings", constants_1.DEFAULT_TEMPLATED_STRING_PREFIX)
.option("-s, --templated-string-suffix <suffix>", "Suffix for templated strings", constants_1.DEFAULT_TEMPLATED_STRING_SUFFIX)
.option("-k, --api-key <API key>", "API key")
.option("-h, --host <hostIP:port>", constants_1.CLI_HELP.OllamaHost)
.option("--ensure-changed-translation", constants_1.CLI_HELP.EnsureChangedTranslation, false)
.option("-n, --batch-size <batchSize>", constants_1.CLI_HELP.BatchSize)
.option("--skip-translation-verification", constants_1.CLI_HELP.SkipTranslationVerification, false)
.option("--skip-styling-verification", constants_1.CLI_HELP.SkipStylingVerification, false)
.option("--override-prompt <path to JSON file>", constants_1.CLI_HELP.OverridePromptFile)
.option("--verbose", constants_1.CLI_HELP.Verbose, false)
.option("--prompt-mode <prompt-mode>", constants_1.CLI_HELP.PromptMode)
.option("--batch-max-tokens <batch-max-tokens>", constants_1.CLI_HELP.MaxTokens)
.option("--dry-run", constants_1.CLI_HELP.DryRun, false)
.action(async (options) => {
const { model, chatParams, rateLimitMs, apiKey, host, promptMode, batchSize, batchMaxTokens, } = (0, cli_helpers_1.processModelArgs)(options);
let overridePrompt;
if (options.overridePrompt) {
overridePrompt = (0, cli_helpers_1.processOverridePromptFile)(options.overridePrompt);
}
let dryRun;
if (options.dryRun) {
dryRun = {
basePath: (0, fs_1.mkdtempSync)(`/tmp/i18n-ai-translate-${new Date().toISOString().replace(/[:.]/g, "-")}-`),
};
}
if (options.outputLanguages) {
if (options.forceLanguageName) {
(0, utils_1.printError)("Cannot use both --output-languages and --force-language");
return;
}
if (options.allLanguages) {
(0, utils_1.printError)("Cannot use both --all-languages and --output-languages");
return;
}
if (options.outputLanguages.length === 0) {
(0, utils_1.printError)("No languages specified");
return;
}
if (options.verbose) {
(0, utils_1.printInfo)(`Translating to ${options.outputLanguages.join(", ")}...`);
}
const jsonFolder = path_1.default.resolve(process.cwd(), "jsons");
let inputPath;
if (path_1.default.isAbsolute(options.input)) {
inputPath = path_1.default.resolve(options.input);
}
else {
inputPath = path_1.default.resolve(jsonFolder, options.input);
if (!fs_1.default.existsSync(inputPath)) {
inputPath = path_1.default.resolve(process.cwd(), options.input);
}
}
if (fs_1.default.statSync(inputPath).isFile()) {
let i = 0;
for (const languageCode of options.outputLanguages) {
i++;
if (options.verbose) {
(0, utils_1.printInfo)(`Translating ${i}/${options.outputLanguages.length} languages...`);
}
const output = (0, utils_1.getOutputPathFromInputPath)(inputPath, languageCode);
if (options.input === output) {
continue;
}
let outputPath;
if (path_1.default.isAbsolute(output)) {
outputPath = path_1.default.resolve(output);
}
else {
outputPath = path_1.default.resolve(jsonFolder, output);
if (!fs_1.default.existsSync(jsonFolder)) {
outputPath = path_1.default.resolve(process.cwd(), output);
}
}
try {
// eslint-disable-next-line no-await-in-loop
await (0, translate_file_1.translateFile)({
apiKey,
batchMaxTokens,
batchSize,
chatParams,
dryRun,
engine: options.engine,
ensureChangedTranslation: options.ensureChangedTranslation,
host,
inputFilePath: inputPath,
model,
outputFilePath: outputPath,
overridePrompt,
promptMode,
rateLimitMs,
skipStylingVerification: options.skipStylingVerification,
skipTranslationVerification: options.skipTranslationVerification,
templatedStringPrefix: options.templatedStringPrefix,
templatedStringSuffix: options.templatedStringSuffix,
verbose: options.verbose,
});
}
catch (err) {
(0, utils_1.printError)(`Failed to translate file to ${languageCode}: ${err}`);
}
}
}
else {
let i = 0;
for (const languageCode of options.outputLanguages) {
i++;
if (options.verbose) {
(0, utils_1.printInfo)(`Translating ${i}/${options.outputLanguages.length} languages...`);
}
const output = (0, utils_1.getOutputPathFromInputPath)(inputPath, languageCode);
if (options.input === output) {
continue;
}
try {
// eslint-disable-next-line no-await-in-loop
await (0, translate_directory_1.translateDirectory)({
apiKey,
baseDirectory: path_1.default.resolve(inputPath, ".."),
batchMaxTokens: options.batchMaxTokens,
batchSize: options.batchSize,
chatParams,
dryRun,
engine: options.engine,
ensureChangedTranslation: options.ensureChangedTranslation,
host,
inputLanguage: path_1.default.basename(inputPath),
model,
outputLanguage: languageCode,
overridePrompt,
promptMode,
rateLimitMs,
skipStylingVerification: options.skipStylingVerification,
skipTranslationVerification: options.skipTranslationVerification,
templatedStringPrefix: options.templatedStringPrefix,
templatedStringSuffix: options.templatedStringSuffix,
verbose: options.verbose,
});
}
catch (err) {
(0, utils_1.printError)(`Failed to translate directory to ${languageCode}: ${err}`);
}
}
}
}
else {
if (options.forceLanguageName) {
(0, utils_1.printError)("Cannot use both --all-languages and --force-language");
return;
}
(0, utils_1.printWarn)("Some languages may fail to translate due to the model's limitations");
let i = 0;
for (const languageCode of (0, utils_1.getAllLanguageCodes)()) {
i++;
if (options.verbose) {
(0, utils_1.printInfo)(`Translating ${i}/${(0, utils_1.getAllLanguageCodes)().length} languages...`);
}
const jsonFolder = path_1.default.resolve(process.cwd(), "jsons");
let inputPath;
if (path_1.default.isAbsolute(options.input)) {
inputPath = path_1.default.resolve(options.input);
}
else {
inputPath = path_1.default.resolve(jsonFolder, options.input);
if (!fs_1.default.existsSync(inputPath)) {
inputPath = path_1.default.resolve(process.cwd(), options.input);
}
}
if (fs_1.default.statSync(inputPath).isFile()) {
const output = (0, utils_1.getOutputPathFromInputPath)(inputPath, languageCode);
if (options.input === output) {
continue;
}
let outputPath;
if (path_1.default.isAbsolute(output)) {
outputPath = path_1.default.resolve(output);
}
else {
outputPath = path_1.default.resolve(jsonFolder, output);
if (!fs_1.default.existsSync(jsonFolder)) {
outputPath = path_1.default.resolve(process.cwd(), output);
}
}
try {
// eslint-disable-next-line no-await-in-loop
await (0, translate_file_1.translateFile)({
apiKey,
batchMaxTokens: options.batchMaxTokens,
batchSize: options.batchSize,
chatParams,
dryRun,
engine: options.engine,
ensureChangedTranslation: options.ensureChangedTranslation,
host,
inputFilePath: inputPath,
model,
outputFilePath: outputPath,
overridePrompt,
promptMode,
rateLimitMs,
skipStylingVerification: options.skipStylingVerification,
skipTranslationVerification: options.skipTranslationVerification,
templatedStringPrefix: options.templatedStringPrefix,
templatedStringSuffix: options.templatedStringSuffix,
verbose: options.verbose,
});
}
catch (err) {
(0, utils_1.printError)(`Failed to translate to ${languageCode}: ${err}`);
}
}
else {
const output = (0, utils_1.getOutputPathFromInputPath)(inputPath, languageCode);
if (options.input === output) {
continue;
}
try {
// eslint-disable-next-line no-await-in-loop
await (0, translate_directory_1.translateDirectory)({
apiKey,
baseDirectory: path_1.default.resolve(inputPath, ".."),
batchMaxTokens: options.batchMaxTokens,
batchSize: options.batchSize,
chatParams,
dryRun,
engine: options.engine,
ensureChangedTranslation: options.ensureChangedTranslation,
host,
inputLanguage: path_1.default.basename(inputPath),
model,
outputLanguage: languageCode,
overridePrompt,
promptMode,
rateLimitMs,
skipStylingVerification: options.skipStylingVerification,
skipTranslationVerification: options.skipTranslationVerification,
templatedStringPrefix: options.templatedStringPrefix,
templatedStringSuffix: options.templatedStringSuffix,
verbose: options.verbose,
});
}
catch (err) {
(0, utils_1.printError)(`Failed to translate directory to ${languageCode}: ${err}`);
}
}
}
}
});
}
//# sourceMappingURL=cli_translate.js.map