Skip to content

Commit e9baeb7

Browse files
committed
refactor(@angular/build): pass missingTranslation per request in i18n inliner
Remove workerData from the i18n inliner worker pool initialization and pass missingTranslation per task in the request payload. This decouples the worker pool from inliner-specific options, allowing worker threads to be safely shared without hardcoding the missingTranslation handling behavior at pool creation time.
1 parent 9580df8 commit e9baeb7

3 files changed

Lines changed: 41 additions & 12 deletions

File tree

packages/angular/build/src/tools/esbuild/i18n-inliner-worker.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import type { Node } from '@oxc-project/types';
1212
import { MagicString } from 'magic-string';
1313
import assert from 'node:assert';
1414
import { deserialize } from 'node:v8';
15-
import { workerData } from 'node:worker_threads';
1615
import { parseSync } from 'oxc-parser';
1716
import { traversePostOrder } from '../oxc/traversal';
1817
import { loadLocaleData } from './i18n-locale-plugin';
@@ -43,6 +42,11 @@ export interface InlineCodeRequest {
4342
* the Worker by reference instead of being copied into it for every request.
4443
*/
4544
translation?: Blob | SharedArrayBuffer;
45+
46+
/**
47+
* How to handle missing translations.
48+
*/
49+
missingTranslation?: 'error' | 'warning' | 'ignore';
4650
}
4751

4852
/**
@@ -77,6 +81,11 @@ export interface InlineFileBatchRequest {
7781
*/
7882
locales: ReadonlyMap<string, Blob | SharedArrayBuffer | undefined>;
7983

84+
/**
85+
* How to handle missing translations.
86+
*/
87+
missingTranslation?: 'error' | 'warning' | 'ignore';
88+
8089
/**
8190
* Whether the file data should be treated as ephemeral and not cached long-term in the Worker.
8291
* Typically true when all remaining locales for the file are processed in a single batch.
@@ -121,11 +130,6 @@ export type InlineFileBatchResult =
121130
results: InlineLocaleResult[];
122131
};
123132

124-
// Extract common options used for inline requests from the Worker context
125-
const { missingTranslation } = (workerData || {}) as {
126-
missingTranslation: 'error' | 'warning' | 'ignore';
127-
};
128-
129133
/**
130134
* Cached file data including code and extracted localization metadata.
131135
*/
@@ -276,6 +280,7 @@ export async function inlineFileBatch(
276280
locale,
277281
await loadTranslation(locale, translation),
278282
request.filename,
283+
request.missingTranslation,
279284
);
280285

281286
return {
@@ -309,6 +314,7 @@ export async function inlineCode(request: InlineCodeRequest): Promise<InlineCode
309314
request.locale,
310315
await loadTranslation(request.locale, request.translation),
311316
request.filename,
317+
request.missingTranslation,
312318
);
313319

314320
return {
@@ -448,6 +454,7 @@ function escapeTemplatePart(part: string): string {
448454
* @param locale The target locale identifier.
449455
* @param translation The translation messages dictionary, or undefined for untranslated locale.
450456
* @param filename The name of the file being transformed.
457+
* @param missingTranslation How to handle missing translations.
451458
* @returns The transformed code, optional remapped source map, and diagnostics.
452459
*/
453460
async function inlineLocalize(
@@ -457,6 +464,7 @@ async function inlineLocalize(
457464
locale: string,
458465
translation: Record<string, ɵParsedTranslation> | undefined,
459466
filename: string,
467+
missingTranslation: 'error' | 'warning' | 'ignore' = 'warning',
460468
) {
461469
const magicString = new MagicString(code);
462470
const { Diagnostics, translate } = await loadLocalizeTools();

packages/angular/build/src/tools/esbuild/i18n-inliner.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,9 @@ export class I18nInliner {
186186
private readonly options: I18nInlinerOptions,
187187
maxThreads?: number,
188188
) {
189-
const { missingTranslation } = options;
190-
191189
this.#workerPool = new WorkerPool({
192190
filename: require.resolve('./i18n-inliner-worker'),
193191
maxThreads,
194-
// Extract options to ensure only the named options are serialized and sent to the worker
195-
workerData: {
196-
missingTranslation,
197-
},
198192
});
199193
}
200194

@@ -514,6 +508,7 @@ export class I18nInliner {
514508
code: codeBlob,
515509
map: mapBlob,
516510
locales: new Map(batchEntries.map((e) => [e.locale, e.translation])),
511+
missingTranslation: this.options.missingTranslation,
517512
ephemeral,
518513
activeLocales,
519514
generation,
@@ -613,6 +608,7 @@ export class I18nInliner {
613608
code: templateCode,
614609
filename: templateId,
615610
locale,
611+
missingTranslation: this.options.missingTranslation,
616612
translation: await serializeTranslation(
617613
translation,
618614
translationIntegrity,

packages/angular/build/src/tools/esbuild/i18n-inliner_spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,31 @@ describe('I18nInliner', () => {
144144
expect(findFile(outputFiles, 'main.js').text).toContain('"Hello"');
145145
});
146146

147+
it('errors and retains the original message when missingTranslation is "error"', async () => {
148+
const { outputFiles, errors, warnings } = await createInliner({
149+
missingTranslation: 'error',
150+
}).inlineForLocale([browserFile('main.js', GREETING_SOURCE)], 'fr', {
151+
unrelated: translationFor('Sans rapport'),
152+
});
153+
154+
expect(errors.length).toBe(1);
155+
expect(errors[0]).toContain('greeting');
156+
expect(warnings).toEqual([]);
157+
expect(findFile(outputFiles, 'main.js').text).toContain('"Hello"');
158+
});
159+
160+
it('ignores missing translations when missingTranslation is "ignore"', async () => {
161+
const { outputFiles, errors, warnings } = await createInliner({
162+
missingTranslation: 'ignore',
163+
}).inlineForLocale([browserFile('main.js', GREETING_SOURCE)], 'fr', {
164+
unrelated: translationFor('Sans rapport'),
165+
});
166+
167+
expect(errors).toEqual([]);
168+
expect(warnings).toEqual([]);
169+
expect(findFile(outputFiles, 'main.js').text).toContain('"Hello"');
170+
});
171+
147172
it('replaces the locale placeholder with the locale being inlined', async () => {
148173
// The placeholder is only inlined for files that use `$localize`, which is where the build
149174
// inserts it, so the message is present alongside it here.

0 commit comments

Comments
 (0)