Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): validate extracted i18n messages …
Browse files Browse the repository at this point in the history
…for duplicates

This change will analyze the extract i18n messages for duplicates and issue warnings for each case.  This provides the same default behavior as the standalone message extractor contained within `@angular/localize`.  Configurability of the behavior of a detected duplicate (ignore, warn, error) will be added in a future feature.
  • Loading branch information
clydin authored and filipesilva committed Nov 2, 2020
1 parent cde05ca commit a7df989
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
28 changes: 27 additions & 1 deletion packages/angular_devkit/build_angular/src/extract-i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,37 @@ export async function execute(
return webpackResult;
}

const basePath = config.context || projectRoot;

const { checkDuplicateMessages } = await import(
// tslint:disable-next-line: trailing-comma
'@angular/localize/src/tools/src/extract/duplicates'
);

// The filesystem is used to create a relative path for each file
// from the basePath. This relative path is then used in the error message.
const checkFileSystem = {
relative(from: string, to: string): string {
return path.relative(from, to);
},
};
const diagnostics = checkDuplicateMessages(
// tslint:disable-next-line: no-any
checkFileSystem as any,
ivyMessages,
'warning',
// tslint:disable-next-line: no-any
basePath as any,
);
if (diagnostics.messages.length > 0) {
context.logger.warn(diagnostics.formatDiagnostics(''));
}

// Serialize all extracted messages
const serializer = await getSerializer(
format,
i18n.sourceLocale,
config.context || projectRoot,
basePath,
useLegacyIds,
);
const content = serializer.serialize(ivyMessages);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ describe('Extract i18n Target', () => {
}
}, 30000);

it('does not emit the application files', async () => {
host.appendToFile('src/app/app.component.html', '<p i18n>i18n test</p>');

const run = await architect.scheduleTarget(extractI18nTargetSpec);

await expectAsync(run.result).toBeResolvedTo(jasmine.objectContaining({ success: true }));

await run.stop();

expect(host.scopedSync().exists(normalize('dist/app/main.js'))).toBeFalse();
}, 30000);

it('shows errors', async () => {
const logger = new logging.Logger('');
const logs: string[] = [];
Expand Down Expand Up @@ -126,4 +138,29 @@ describe('Extract i18n Target', () => {
expect(virtualFs.fileBufferToString(host.scopedSync().read(extractionFile)))
.toMatch(/i18n test/);
}, 30000);

// DISABLED_FOR_VE
(veEnabled ? xit : it)('issues warnings for duplicate message identifiers', async () => {
host.appendToFile(
'src/app/app.component.ts',
'const c = $localize`:@@message-2:message contents`; const d = $localize`:@@message-2:different message contents`;',
);

const logger = new logging.Logger('');
const logs: string[] = [];
logger.subscribe((e) => logs.push(e.message));

const run = await architect.scheduleTarget(extractI18nTargetSpec, undefined, { logger });
await expectAsync(run.result).toBeResolvedTo(jasmine.objectContaining({ success: true }));

await run.stop();

expect(host.scopedSync().exists(extractionFile)).toBe(true);

const fullLog = logs.join();
expect(fullLog).toContain(
'Duplicate messages with id',
);

}, 30000);
});

0 comments on commit a7df989

Please sign in to comment.