Skip to content

Commit 822bd51

Browse files
fix(compiler-cli): compute the correct target output for $localize messages
In some versions of TypeScript, the transformation of synthetic `$localize` tagged template literals is broken. See microsoft/TypeScript#38485 We now compute what the expected final output target of the compilation will be so that we can generate ES5 compliant `$localize` calls instead of relying upon TS to do the downleveling for us. This is a workaround for the TS compiler bug, which could be removed when this is fixed. But since it only affects ES5 targeted compilations, which is now not the norm, it has limited impact on the majority of Angular projects. So this fix can probably be left in indefinitely.
1 parent 7dd1319 commit 822bd51

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

packages/compiler-cli/src/ngtsc/transform/src/transform.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ function transformIvySourceFile(
233233
// Generate the constant statements first, as they may involve adding additional imports
234234
// to the ImportManager.
235235
const constants = constantPool.statements.map(
236-
stmt =>
237-
translateStatement(stmt, importManager, defaultImportRecorder, ts.ScriptTarget.ES2015));
236+
stmt => translateStatement(
237+
stmt, importManager, defaultImportRecorder, getLocalizeCompileTarget(context)));
238238

239239
// Preserve @fileoverview comments required by Closure, since the location might change as a
240240
// result of adding extra imports and constant pool statements.
@@ -250,6 +250,22 @@ function transformIvySourceFile(
250250
return sf;
251251
}
252252

253+
/**
254+
* Compute the correct target output for `$localize` messages generated by Angular
255+
*
256+
* In some versions of TypeScript, the transformation of synthetic `$localize` tagged template
257+
* literals is broken. See https://github.com/microsoft/TypeScript/issues/38485
258+
*
259+
* Here we compute what the expected final output target of the compilation will
260+
* be so that we can generate ES5 compliant `$localize` calls instead of relying upon TS to do the
261+
* downleveling for us.
262+
*/
263+
function getLocalizeCompileTarget(context: ts.TransformationContext):
264+
Exclude<ts.ScriptTarget, ts.ScriptTarget.JSON> {
265+
const target = context.getCompilerOptions().target || ts.ScriptTarget.ES2015;
266+
return target !== ts.ScriptTarget.JSON ? target : ts.ScriptTarget.ES2015;
267+
}
268+
253269
function getFileOverviewComment(statements: ts.NodeArray<ts.Statement>): FileOverviewMeta|null {
254270
if (statements.length > 0) {
255271
const host = statements[0];

packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
98
import {AttributeMarker} from '@angular/compiler/src/core';
109
import {setup} from '@angular/compiler/test/aot/test_util';
10+
import * as ts from 'typescript';
1111

1212
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../compiler/src/compiler';
1313
import {decimalDigest} from '../../../compiler/src/i18n/digest';
@@ -3761,6 +3761,23 @@ $` + String.raw`{$I18N_4$}:ICU:\`;
37613761
}));
37623762
});
37633763

3764+
describe('es5 support', () => {
3765+
it('should generate ES5 compliant localized messages if the target is ES5', () => {
3766+
const input = `
3767+
<div i18n="meaning:A|descA@@idA">Content A</div>
3768+
`;
3769+
3770+
const output = String.raw`
3771+
var $I18N_0$;
3772+
3773+
$I18N_0$ = $localize(…__makeTemplateObject([":meaning:A|descA@@idA:Content A"], [":meaning\\:A|descA@@idA:Content A"])…);
3774+
`;
3775+
3776+
verify(
3777+
input, output, {skipIdBasedCheck: true, compilerOptions: {target: ts.ScriptTarget.ES5}});
3778+
});
3779+
});
3780+
37643781
describe('errors', () => {
37653782
const verifyNestedSectionsError = (errorThrown: any, expectedErrorText: string) => {
37663783
expect(errorThrown.ngParseErrors.length).toBe(1);

0 commit comments

Comments
 (0)