eb999300d9
Previously the compiler compliance tests ran and built test code with real dependencies on @angular/core and @angular/common. This meant that any changes to the compiler would result in long rebuild processes for tests to rerun. This change removes those dependencies and causes test code to be built against the fake_core stub of @angular/core that the ngtsc tests use. This change also removes the dependency on @angular/common entirely, as locality means it's possible to reference *ngIf without needing to link to an implementation. PR Close #25248
226 lines
5.8 KiB
TypeScript
226 lines
5.8 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {MockDirectory, setup} from '@angular/compiler/test/aot/test_util';
|
|
import {compile, expectEmit} from './mock_compile';
|
|
|
|
const TRANSLATION_NAME_REGEXP = /^MSG_[A-Z0-9]+/;
|
|
|
|
describe('i18n support in the view compiler', () => {
|
|
const angularFiles = setup({
|
|
compileAngular: false,
|
|
compileFakeCore: true,
|
|
compileAnimations: false,
|
|
});
|
|
|
|
describe('single text nodes', () => {
|
|
it('should translate single text nodes with the i18n attribute', () => {
|
|
const files = {
|
|
app: {
|
|
'spec.ts': `
|
|
import {Component, NgModule} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'my-component',
|
|
template: \`
|
|
<div i18n>Hello world</div>
|
|
<div>&</div>
|
|
<div i18n>farewell</div>
|
|
<div i18n>farewell</div>
|
|
\`
|
|
})
|
|
export class MyComponent {}
|
|
|
|
@NgModule({declarations: [MyComponent]})
|
|
export class MyModule {}
|
|
`
|
|
}
|
|
};
|
|
|
|
const template = `
|
|
const $msg_1$ = goog.getMsg("Hello world");
|
|
const $msg_2$ = goog.getMsg("farewell");
|
|
…
|
|
template: function MyComponent_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
…
|
|
$r3$.ɵT(1, $msg_1$);
|
|
…
|
|
$r3$.ɵT(3,"&");
|
|
…
|
|
$r3$.ɵT(5, $msg_2$);
|
|
…
|
|
$r3$.ɵT(7, $msg_2$);
|
|
…
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = compile(files, angularFiles);
|
|
expectEmit(result.source, template, 'Incorrect template', {
|
|
'$msg_1$': TRANSLATION_NAME_REGEXP,
|
|
'$msg_2$': TRANSLATION_NAME_REGEXP,
|
|
});
|
|
});
|
|
|
|
it('should add the meaning and description as JsDoc comments', () => {
|
|
const files = {
|
|
app: {
|
|
'spec.ts': `
|
|
import {Component, NgModule} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'my-component',
|
|
template: \`
|
|
<div i18n="meaning|desc@@id" i18n-title="desc" title="introduction">Hello world</div>
|
|
\`
|
|
})
|
|
export class MyComponent {}
|
|
|
|
@NgModule({declarations: [MyComponent]})
|
|
export class MyModule {}
|
|
`
|
|
}
|
|
};
|
|
|
|
const template = `
|
|
/**
|
|
* @desc desc
|
|
*/
|
|
const $msg_1$ = goog.getMsg("introduction");
|
|
const $c1$ = ["title", $msg_1$];
|
|
…
|
|
/**
|
|
* @desc desc
|
|
* @meaning meaning
|
|
*/
|
|
const $msg_2$ = goog.getMsg("Hello world");
|
|
…
|
|
template: function MyComponent_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
$r3$.ɵE(0, "div", $c1$);
|
|
$r3$.ɵT(1, $msg_2$);
|
|
$r3$.ɵe();
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = compile(files, angularFiles);
|
|
expectEmit(result.source, template, 'Incorrect template', {
|
|
'$msg_1$': TRANSLATION_NAME_REGEXP,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('static attributes', () => {
|
|
it('should translate static attributes', () => {
|
|
const files = {
|
|
app: {
|
|
'spec.ts': `
|
|
import {Component, NgModule} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'my-component',
|
|
template: \`
|
|
<div i18n id="static" i18n-title="m|d" title="introduction"></div>
|
|
\`
|
|
})
|
|
export class MyComponent {}
|
|
|
|
@NgModule({declarations: [MyComponent]})
|
|
export class MyModule {}
|
|
`
|
|
}
|
|
};
|
|
|
|
const template = `
|
|
/**
|
|
* @desc d
|
|
* @meaning m
|
|
*/
|
|
const $msg_1$ = goog.getMsg("introduction");
|
|
const $c1$ = ["id", "static", "title", $msg_1$];
|
|
…
|
|
template: function MyComponent_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
$r3$.ɵEe(0, "div", $c1$);
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = compile(files, angularFiles);
|
|
expectEmit(result.source, template, 'Incorrect template', {
|
|
'$msg_1$': TRANSLATION_NAME_REGEXP,
|
|
});
|
|
});
|
|
});
|
|
|
|
// TODO(vicb): this feature is not supported yet
|
|
xdescribe('nested nodes', () => {
|
|
it('should generate the placeholders maps', () => {
|
|
const files = {
|
|
app: {
|
|
'spec.ts': `
|
|
import {Component, NgModule} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'my-component',
|
|
template: \`
|
|
<div i18n>Hello <b>{{name}}<i>!</i><i>!</i></b></div>
|
|
<div>Other</div>
|
|
<div i18n>2nd</div>
|
|
<div i18n><i>3rd</i></div>
|
|
\`
|
|
})
|
|
export class MyComponent {}
|
|
|
|
@NgModule({declarations: [MyComponent]})
|
|
export class MyModule {}
|
|
`
|
|
}
|
|
};
|
|
|
|
const template = `
|
|
const $r1$ = {"b":[2], "i":[4, 6]};
|
|
const $r2$ = {"i":[13]};
|
|
`;
|
|
|
|
const result = compile(files, angularFiles);
|
|
expectEmit(result.source, template, 'Incorrect template');
|
|
});
|
|
});
|
|
|
|
describe('errors', () => {
|
|
it('should throw on nested i18n sections', () => {
|
|
const files = {
|
|
app: {
|
|
'spec.ts': `
|
|
import {Component, NgModule} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'my-component',
|
|
template: \`
|
|
<div i18n><div i18n></div></div>
|
|
\`
|
|
})
|
|
export class MyComponent {}
|
|
|
|
@NgModule({declarations: [MyComponent]})
|
|
export class MyModule {}
|
|
`
|
|
}
|
|
};
|
|
|
|
expect(() => compile(files, angularFiles))
|
|
.toThrowError(
|
|
'Could not mark an element as translatable inside of a translatable section');
|
|
});
|
|
|
|
});
|
|
});
|