Skip to content

Commit 2243c1a

Browse files
committed
feat: add batch size parameter to prevent context leaking (closes #1733)
1 parent 10e8cef commit 2243c1a

File tree

10 files changed

+362
-108
lines changed

10 files changed

+362
-108
lines changed

packages/cli/src/cli/cmd/i18n.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ export default new Command()
9090
"--strict",
9191
"Stop immediately on first error instead of continuing to process remaining buckets and locales (fail-fast mode)",
9292
)
93+
.option(
94+
"--batch-size <number>",
95+
"Number of translations to process in a single batch",
96+
parseInt,
97+
)
9398
.action(async function (options) {
9499
updateGitignore();
95100

@@ -432,14 +437,14 @@ export default new Command()
432437
}
433438

434439
bucketOra.start(
435-
`[${sourceLocale} -> ${targetLocale}] [${
436-
Object.keys(processableData).length
440+
`[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length
437441
} entries] (0%) AI localization in progress...`,
438442
);
439443
let processPayload = createProcessor(i18nConfig!.provider, {
440444
apiKey: settings.auth.apiKey,
441445
apiUrl: settings.auth.apiUrl,
442446
engineId: i18nConfig!.engineId,
447+
batchSize: flags.batchSize,
443448
});
444449
processPayload = withExponentialBackoff(
445450
processPayload,
@@ -457,9 +462,8 @@ export default new Command()
457462
targetData: flags.force ? {} : targetData,
458463
},
459464
(progress, sourceChunk, processedChunk) => {
460-
bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${
461-
Object.keys(processableData).length
462-
} entries] (${progress}%) AI localization in progress...`;
465+
bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length
466+
} entries] (${progress}%) AI localization in progress...`;
463467
},
464468
);
465469

@@ -662,6 +666,7 @@ function parseFlags(options: any) {
662666
file: Z.array(Z.string()).optional(),
663667
interactive: Z.boolean().prefault(false),
664668
debug: Z.boolean().prefault(false),
669+
batchSize: Z.number().min(1).optional(),
665670
}).parse(options);
666671
}
667672

packages/cli/src/cli/cmd/run/_types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ export const flagsSchema = z.object({
5656
debounce: z.number().positive().prefault(5000), // 5 seconds default
5757
sound: z.boolean().optional(),
5858
pseudo: z.boolean().optional(),
59+
batchSize: z.number().min(1).optional(),
5960
});
6061
export type CmdRunFlags = z.infer<typeof flagsSchema>;

packages/cli/src/cli/cmd/run/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ export default new Command()
123123
"--pseudo",
124124
"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",
125125
)
126+
.option(
127+
"--batch-size <number>",
128+
"Number of translations to process in a single batch",
129+
(val: string) => parseInt(val),
130+
)
126131
.action(async (args) => {
127132
let userIdentity: UserIdentity = null;
128133
try {

packages/cli/src/cli/cmd/run/setup.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ export default async function setup(input: CmdRunContext) {
5454
ctx.flags.pseudo || ctx.config?.dev?.usePseudotranslator;
5555
const provider = isPseudo ? "pseudo" : ctx.config?.provider;
5656
const engineId = ctx.config?.engineId;
57-
ctx.localizer = createLocalizer(provider, engineId, ctx.flags.apiKey);
57+
ctx.localizer = createLocalizer(
58+
provider,
59+
engineId,
60+
ctx.flags.apiKey,
61+
ctx.flags.batchSize,
62+
);
5863
if (!ctx.localizer) {
5964
throw new Error(
6065
"Could not create localization provider. Please check your i18n.json configuration.",
@@ -105,23 +110,23 @@ export default async function setup(input: CmdRunContext) {
105110

106111
const subTasks = isLingoDotDev
107112
? [
108-
"Brand voice enabled",
109-
"Translation memory connected",
110-
"Glossary enabled",
111-
"Quality assurance enabled",
112-
].map((title) => ({ title, task: () => {} }))
113+
"Brand voice enabled",
114+
"Translation memory connected",
115+
"Glossary enabled",
116+
"Quality assurance enabled",
117+
].map((title) => ({ title, task: () => { } }))
113118
: isPseudo
114119
? [
115-
"Pseudo-localization mode active",
116-
"Character replacement configured",
117-
"No external API calls",
118-
].map((title) => ({ title, task: () => {} }))
120+
"Pseudo-localization mode active",
121+
"Character replacement configured",
122+
"No external API calls",
123+
].map((title) => ({ title, task: () => { } }))
119124
: [
120-
"Skipping brand voice",
121-
"Skipping glossary",
122-
"Skipping translation memory",
123-
"Skipping quality assurance",
124-
].map((title) => ({ title, task: () => {}, skip: true }));
125+
"Skipping brand voice",
126+
"Skipping glossary",
127+
"Skipping translation memory",
128+
"Skipping quality assurance",
129+
].map((title) => ({ title, task: () => { }, skip: true }));
125130

126131
return task.newListr(subTasks, {
127132
concurrent: true,

0 commit comments

Comments
 (0)