2018-02-14 13:54:00 -05:00
|
|
|
/**
|
|
|
|
* @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 {setup} from '../aot/test_util';
|
|
|
|
import {compile, expectEmit} from './mock_compile';
|
|
|
|
|
2018-03-23 13:37:40 -04:00
|
|
|
const TRANSLATION_NAME_REGEXP = /^MSG_[A-Z0-9]+/;
|
|
|
|
|
2018-02-14 13:54:00 -05:00
|
|
|
describe('i18n support in the view compiler', () => {
|
|
|
|
const angularFiles = setup({
|
|
|
|
compileAngular: true,
|
|
|
|
compileAnimations: false,
|
|
|
|
compileCommon: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
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>
|
2018-03-22 18:03:06 -04:00
|
|
|
<div i18n>farewell</div>
|
2018-02-14 13:54:00 -05:00
|
|
|
\`
|
|
|
|
})
|
|
|
|
export class MyComponent {}
|
|
|
|
|
|
|
|
@NgModule({declarations: [MyComponent]})
|
|
|
|
export class MyModule {}
|
|
|
|
`
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const template = `
|
2018-03-22 18:03:06 -04:00
|
|
|
const $msg_1$ = goog.getMsg('Hello world');
|
|
|
|
const $msg_2$ = goog.getMsg('farewell');
|
|
|
|
…
|
2018-04-10 23:57:20 -04:00
|
|
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
|
|
|
if (rf & 1) {
|
2018-02-14 13:54:00 -05:00
|
|
|
…
|
2018-03-22 18:03:06 -04:00
|
|
|
$r3$.ɵT(1, $msg_1$);
|
2018-02-14 13:54:00 -05:00
|
|
|
…
|
|
|
|
$r3$.ɵT(3,'&');
|
|
|
|
…
|
2018-03-22 18:03:06 -04:00
|
|
|
$r3$.ɵT(5, $msg_2$);
|
|
|
|
…
|
|
|
|
$r3$.ɵT(7, $msg_2$);
|
2018-02-14 13:54:00 -05:00
|
|
|
…
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
const result = compile(files, angularFiles);
|
2018-03-23 13:37:40 -04:00
|
|
|
expectEmit(result.source, template, 'Incorrect template', {
|
|
|
|
'$msg_1$': TRANSLATION_NAME_REGEXP,
|
|
|
|
'$msg_2$': TRANSLATION_NAME_REGEXP,
|
|
|
|
});
|
2018-02-14 13:54:00 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
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 = `
|
2018-03-22 18:03:06 -04:00
|
|
|
/**
|
|
|
|
* @desc desc
|
|
|
|
*/
|
|
|
|
const $msg_1$ = goog.getMsg('introduction');
|
2018-05-10 18:58:27 -04:00
|
|
|
const $c1$ = ['title', $msg_1$];
|
2018-02-14 13:54:00 -05:00
|
|
|
…
|
2018-03-22 18:03:06 -04:00
|
|
|
/**
|
|
|
|
* @desc desc
|
|
|
|
* @meaning meaning
|
|
|
|
*/
|
|
|
|
const $msg_2$ = goog.getMsg('Hello world');
|
|
|
|
…
|
2018-04-10 23:57:20 -04:00
|
|
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
|
|
|
if (rf & 1) {
|
2018-05-10 18:58:27 -04:00
|
|
|
$r3$.ɵE(0, 'div', $c1$);
|
2018-03-22 18:03:06 -04:00
|
|
|
$r3$.ɵT(1, $msg_2$);
|
2018-02-14 13:54:00 -05:00
|
|
|
$r3$.ɵe();
|
|
|
|
}
|
|
|
|
}
|
2018-03-22 18:03:06 -04:00
|
|
|
`;
|
2018-02-14 13:54:00 -05:00
|
|
|
|
|
|
|
const result = compile(files, angularFiles);
|
2018-03-23 13:37:40 -04:00
|
|
|
expectEmit(result.source, template, 'Incorrect template', {
|
|
|
|
'$msg_1$': TRANSLATION_NAME_REGEXP,
|
|
|
|
});
|
2018-02-14 13:54:00 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
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 = `
|
2018-03-22 18:03:06 -04:00
|
|
|
/**
|
|
|
|
* @desc d
|
|
|
|
* @meaning m
|
|
|
|
*/
|
|
|
|
const $msg_1$ = goog.getMsg('introduction');
|
2018-05-10 18:58:27 -04:00
|
|
|
const $c1$ = ['id', 'static', 'title', $msg_1$];
|
2018-02-14 13:54:00 -05:00
|
|
|
…
|
2018-04-10 23:57:20 -04:00
|
|
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
|
|
|
if (rf & 1) {
|
2018-05-10 18:58:27 -04:00
|
|
|
$r3$.ɵE(0, 'div', $c1$);
|
2018-02-14 13:54:00 -05:00
|
|
|
$r3$.ɵe();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
const result = compile(files, angularFiles);
|
2018-03-23 13:37:40 -04:00
|
|
|
expectEmit(result.source, template, 'Incorrect template', {
|
|
|
|
'$msg_1$': TRANSLATION_NAME_REGEXP,
|
|
|
|
});
|
2018-02-14 13:54:00 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// 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');
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|