Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-batch-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"lingo.dev": minor
---

feat: add `--batch-size` parameter to `run` and `i18n` commands to prevent context leaking
15 changes: 10 additions & 5 deletions packages/cli/src/cli/cmd/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ export default new Command()
"--strict",
"Stop immediately on first error instead of continuing to process remaining buckets and locales (fail-fast mode)",
)
.option(
"--batch-size <number>",
"Number of translations to process in a single batch",
parseInt,
)
.action(async function (options) {
updateGitignore();

Expand Down Expand Up @@ -429,13 +434,13 @@ export default new Command()
}

bucketOra.start(
`[${sourceLocale} -> ${targetLocale}] [${
Object.keys(processableData).length
`[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length
} entries] (0%) AI localization in progress...`,
);
let processPayload = createProcessor(i18nConfig!.provider, {
apiKey: settings.auth.apiKey,
apiUrl: settings.auth.apiUrl,
batchSize: flags.batchSize,
});
processPayload = withExponentialBackoff(
processPayload,
Expand All @@ -453,9 +458,8 @@ export default new Command()
targetData: flags.force ? {} : targetData,
},
(progress, sourceChunk, processedChunk) => {
bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${
Object.keys(processableData).length
} entries] (${progress}%) AI localization in progress...`;
bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length
} entries] (${progress}%) AI localization in progress...`;
},
);

Expand Down Expand Up @@ -657,6 +661,7 @@ function parseFlags(options: any) {
file: Z.array(Z.string()).optional(),
interactive: Z.boolean().prefault(false),
debug: Z.boolean().prefault(false),
batchSize: Z.number().min(1).optional(),
}).parse(options);
}

Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/cli/cmd/run/_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ export const flagsSchema = z.object({
debounce: z.number().positive().prefault(5000), // 5 seconds default
sound: z.boolean().optional(),
pseudo: z.boolean().optional(),
batchSize: z.number().min(1).optional(),
});
export type CmdRunFlags = z.infer<typeof flagsSchema>;
5 changes: 5 additions & 0 deletions packages/cli/src/cli/cmd/run/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ export default new Command()
"--pseudo",
"Enable pseudo-localization mode: automatically pseudo-translates all extracted strings with accented characters and visual markers without calling any external API. Useful for testing UI internationalization readiness",
)
.option(
"--batch-size <number>",
"Number of translations to process in a single batch (not applicable when using lingo.dev provider)",
(val: string) => parseInt(val),
)
.action(async (args) => {
let email: string | null = null;
try {
Expand Down
37 changes: 21 additions & 16 deletions packages/cli/src/cli/cmd/run/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,20 @@ export default async function setup(input: CmdRunContext) {
task: async (ctx, task) => {
const provider = ctx.flags.pseudo ? "pseudo" : ctx.config?.provider;
const vNext = ctx.config?.vNext;
ctx.localizer = createLocalizer(provider, ctx.flags.apiKey, vNext);
ctx.localizer = createLocalizer(
provider,
ctx.flags.apiKey,
vNext,
ctx.flags.batchSize,
);
if (!ctx.localizer) {
throw new Error(
"Could not create localization provider. Please check your i18n.json configuration.",
);
}
task.title =
ctx.localizer.id === "Lingo.dev" ||
ctx.localizer.id === "Lingo.dev vNext"
ctx.localizer.id === "Lingo.dev vNext"
? `Using ${chalk.hex(colors.green)(ctx.localizer.id)} provider`
: ctx.localizer.id === "pseudo"
? `Using ${chalk.hex(colors.blue)("pseudo")} mode for testing`
Expand Down Expand Up @@ -108,23 +113,23 @@ export default async function setup(input: CmdRunContext) {

const subTasks = isLingoDotDev
? [
"Brand voice enabled",
"Translation memory connected",
"Glossary enabled",
"Quality assurance enabled",
].map((title) => ({ title, task: () => {} }))
"Brand voice enabled",
"Translation memory connected",
"Glossary enabled",
"Quality assurance enabled",
].map((title) => ({ title, task: () => { } }))
: isPseudo
? [
"Pseudo-localization mode active",
"Character replacement configured",
"No external API calls",
].map((title) => ({ title, task: () => {} }))
"Pseudo-localization mode active",
"Character replacement configured",
"No external API calls",
].map((title) => ({ title, task: () => { } }))
: [
"Skipping brand voice",
"Skipping glossary",
"Skipping translation memory",
"Skipping quality assurance",
].map((title) => ({ title, task: () => {}, skip: true }));
"Skipping brand voice",
"Skipping glossary",
"Skipping translation memory",
"Skipping quality assurance",
].map((title) => ({ title, task: () => { }, skip: true }));
Comment on lines -111 to +132
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where all the whitespace changes come from, but it adds a significant amount of noise to the changeset


return task.newListr(subTasks, {
concurrent: true,
Expand Down
Loading