Skip to content

Commit dcd4439

Browse files
committed
feat(@angular-devkit/build-angular): watch i18n translation files with dev server
When using i18n with the dev server, the translation files will now be linked as a dependency to any file containing translated text. This allows translation files to be watched and the application to be rebuilt using the changed translation files. This change should also provide some performance improvements as well since now only files containing `$localize` will be parsed and processed by the babel-based localization inliner. Closes #16341
1 parent 2fec1c0 commit dcd4439

2 files changed

Lines changed: 41 additions & 4 deletions

File tree

packages/angular_devkit/build_angular/src/babel/webpack-loader.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,19 @@ export default custom<AngularCustomOptions>(() => {
108108
!/[\\\/]@angular[\\\/](?:compiler|localize)/.test(this.resourcePath) &&
109109
source.includes('$localize')
110110
) {
111-
customOptions.i18n = i18n as ApplicationPresetOptions['i18n'];
111+
const { translationFiles, ...i18nOptions } = i18n as ApplicationPresetOptions['i18n'] & {
112+
translationFiles?: string[];
113+
};
114+
customOptions.i18n = i18nOptions;
115+
116+
// Add translation files as dependencies of the file to support rebuilds
117+
// Except for `@angular/core` which needs locale injection but has no translations
118+
if (translationFiles && !/[\\\/]@angular[\\\/]core/.test(this.resourcePath)) {
119+
for (const file of translationFiles) {
120+
this.addDependency(file);
121+
}
122+
}
123+
112124
shouldProcess = true;
113125
}
114126

packages/angular_devkit/build_angular/src/dev-server/index.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ export function serveWebpackBrowser(
242242
);
243243
}
244244

245-
await setupLocalize(locale, i18n, browserOptions, webpackConfig);
245+
await setupLocalize(locale, i18n, browserOptions, webpackConfig, context);
246246
}
247247
}
248248

@@ -352,6 +352,7 @@ async function setupLocalize(
352352
i18n: I18nOptions,
353353
browserOptions: BrowserBuilderSchema,
354354
webpackConfig: webpack.Configuration,
355+
context: BuilderContext,
355356
) {
356357
const localeDescription = i18n.locales[locale];
357358

@@ -371,16 +372,21 @@ async function setupLocalize(
371372

372373
let missingTranslationBehavior = browserOptions.i18nMissingTranslation || 'ignore';
373374
let translation = localeDescription?.translation || {};
375+
const sourceLocale = i18n.sourceLocale;
376+
const shouldInline = i18n.shouldInline;
374377

375-
if (locale === i18n.sourceLocale) {
378+
if (locale === sourceLocale) {
376379
missingTranslationBehavior = 'ignore';
377380
translation = {};
378381
}
379382

380383
const i18nLoaderOptions = {
381384
locale,
382385
missingTranslationBehavior,
383-
translation: i18n.shouldInline ? translation : undefined,
386+
translation: shouldInline ? translation : undefined,
387+
translationFiles: localeDescription?.files.map((file) =>
388+
path.resolve(context.workspaceRoot, file.path),
389+
),
384390
};
385391

386392
const i18nRule: webpack.RuleSetRule = {
@@ -410,6 +416,25 @@ async function setupLocalize(
410416
}
411417

412418
rules.push(i18nRule);
419+
420+
// Add a plugin to reload translation files on rebuilds
421+
// tslint:disable-next-line: no-non-null-assertion
422+
webpackConfig.plugins!.push({
423+
apply: (compiler: webpack.Compiler) => {
424+
compiler.hooks.thisCompilation.tap('build-angular', compilation => {
425+
if (shouldInline && i18nLoaderOptions.translation === undefined) {
426+
// Reload translation
427+
// NOTE: This could be further optimized by checking if any translation file actually changed
428+
429+
}
430+
431+
compilation.hooks.finishModules.tap('build-angular', () => {
432+
// After loaders are finished, clear out the now unneeded translations
433+
i18nLoaderOptions.translation = undefined;
434+
});
435+
});
436+
},
437+
});
413438
}
414439

415440
export default createBuilder<DevServerBuilderOptions, DevServerBuilderOutput>(serveWebpackBrowser);

0 commit comments

Comments
 (0)