feat(ivy): updated translation const names (that include message ids) (#27185)

PR Close #27185
This commit is contained in:
Andrew Kushnir
2018-11-16 09:57:23 -08:00
committed by Igor Minar
parent 9129f9ac9b
commit aedc343003
15 changed files with 482 additions and 526 deletions

View File

@ -60,7 +60,7 @@ export class DecorationAnalyzer {
new BaseDefDecoratorHandler(this.typeChecker, this.host),
new ComponentDecoratorHandler(
this.typeChecker, this.host, this.scopeRegistry, this.isCore, this.resourceLoader,
this.rootDirs, /* defaultPreserveWhitespaces */ false),
this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true),
new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.host, this.isCore),
new NgModuleDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),

View File

@ -40,7 +40,7 @@ export class ComponentDecoratorHandler implements
private checker: ts.TypeChecker, private reflector: ReflectionHost,
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean,
private resourceLoader: ResourceLoader, private rootDirs: string[],
private defaultPreserveWhitespaces: boolean) {}
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {}
private literalCache = new Map<Decorator, ts.ObjectLiteralExpression>();
private elementSchemaRegistry = new DomElementSchemaRegistry();
@ -131,7 +131,7 @@ export class ComponentDecoratorHandler implements
// Go through the root directories for this project, and select the one with the smallest
// relative path representation.
const filePath = node.getSourceFile().fileName;
const relativeFilePath = this.rootDirs.reduce<string|undefined>((previous, rootDir) => {
const relativeContextFilePath = this.rootDirs.reduce<string|undefined>((previous, rootDir) => {
const candidate = path.posix.relative(rootDir, filePath);
if (previous === undefined || candidate.length < previous.length) {
return candidate;
@ -142,7 +142,7 @@ export class ComponentDecoratorHandler implements
const template = parseTemplate(
templateStr, `${node.getSourceFile().fileName}#${node.name!.text}/template.html`,
{preserveWhitespaces}, relativeFilePath);
{preserveWhitespaces});
if (template.errors !== undefined) {
throw new Error(
`Errors parsing template: ${template.errors.map(e => e.toString()).join(', ')}`);
@ -212,7 +212,8 @@ export class ComponentDecoratorHandler implements
directives: EMPTY_ARRAY,
wrapDirectivesAndPipesInClosure: false, //
animations,
viewProviders
viewProviders,
i18nUseExternalIds: this.i18nUseExternalIds, relativeContextFilePath
},
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore),
parsedTemplate: template.nodes,

View File

@ -40,7 +40,7 @@ describe('ComponentDecoratorHandler', () => {
const host = new TypeScriptReflectionHost(checker);
const handler = new ComponentDecoratorHandler(
checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(),
[''], false);
[''], false, true);
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration);
const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp));
if (detected === undefined) {

View File

@ -220,7 +220,7 @@ export class NgtscProgram implements api.Program {
new BaseDefDecoratorHandler(checker, this.reflector),
new ComponentDecoratorHandler(
checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs,
this.options.preserveWhitespaces || false),
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false),
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.reflector, this.isCore),
new NgModuleDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),

View File

@ -151,6 +151,9 @@ export interface CompilerOptions extends ts.CompilerOptions {
i18nInFile?: string;
// How to handle missing messages
i18nInMissingTranslations?: 'error'|'warning'|'ignore';
// Whether translation variable name should contain external message id
// (used by Closure Compiler's output of `goog.getMsg` for transition period)
i18nUseExternalIds?: boolean;
// Whether to remove blank text nodes from compiled templates. It is `false` by default starting
// from Angular 6.

View File

@ -935,7 +935,8 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions {
return {
locale: options.i18nInLocale,
i18nFormat: options.i18nInFormat || options.i18nOutFormat, translations, missingTranslation,
i18nFormat: options.i18nInFormat || options.i18nOutFormat,
i18nUseExternalIds: options.i18nUseExternalIds, translations, missingTranslation,
enableSummariesForJit: options.enableSummariesForJit,
preserveWhitespaces: options.preserveWhitespaces,
fullTemplateTypeCheck: options.fullTemplateTypeCheck,

View File

@ -553,6 +553,26 @@ describe('ngtsc behavioral tests', () => {
expect(trim(jsContents)).toContain(trim(hostBindingsFn));
});
it('should use proper default value for preserveWhitespaces config param', () => {
env.tsconfig(); // default is `false`
env.write(`test.ts`, `
import {Component} from '@angular/core';
@Component({
selector: 'test',
preserveWhitespaces: false,
template: \`
<div>
Template with whitespaces
</div>
\`
})
class FooCmp {}
`);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).toContain('text(1, " Template with whitespaces ");');
});
it('should take preserveWhitespaces config option into account', () => {
env.tsconfig({preserveWhitespaces: true});
env.write(`test.ts`, `
@ -593,6 +613,36 @@ describe('ngtsc behavioral tests', () => {
expect(jsContents).toContain('text(1, " Template with whitespaces ");');
});
it('should use proper default value for i18nUseExternalIds config param', () => {
env.tsconfig(); // default is `true`
env.write(`test.ts`, `
import {Component} from '@angular/core';
@Component({
selector: 'test',
template: '<div i18n>Some text</div>'
})
class FooCmp {}
`);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).toContain('i18n(1, MSG_EXTERNAL_8321000940098097247);');
});
it('should take i18nUseExternalIds config option into account', () => {
env.tsconfig({i18nUseExternalIds: false});
env.write(`test.ts`, `
import {Component} from '@angular/core';
@Component({
selector: 'test',
template: '<div i18n>Some text</div>'
})
class FooCmp {}
`);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).toContain('i18n(1, MSG_TEST_TS_0);');
});
it('should correctly recognize local symbols', () => {
env.tsconfig();
env.write('module.ts', `