/**
* @license
* Copyright Google LLC 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 * as fs from 'fs';
import * as path from 'path';
import {mainXi18n} from '../src/extract_i18n';
import {setup} from './test_support';
const EXPECTED_XMB = `
]>
translate me
Welcome
{VAR_PLURAL, plural, =1 {book} other {books} }
foo { count, plural, =1 {...} other {...}}{ count, plural, =1 {...} other {...}}
Name: <b><b>{{
name // i18n(ph="name")
}}{{
name // i18n(ph="name")
}}</b></b>
`;
const EXPECTED_XLIFF = `
src/basic.html
1
src/comp2.ts
1
src/basic.html
1
desc
meaning
src/basic.html
3
src/comp2.ts
3
src/comp2.ts
2
src/basic.html
3
src/icu.html
1
with ICU
src/icu.html
4
with ICU and other things
src/icu.html
5
src/placeholders.html
1
with placeholders
`;
const EXPECTED_XLIFF2 = `
desc
meaning
src/basic.html:1
src/comp2.ts:1
src/basic.html:1
src/basic.html:3,4
src/comp2.ts:3,4
src/comp2.ts:2,3
src/basic.html:3,4
with ICU
src/icu.html:1,3
src/icu.html:5
with ICU and other things
src/icu.html:4,6
with placeholders
src/placeholders.html:1,3
`;
describe('extract_i18n command line', () => {
let basePath: string;
let outDir: string;
let write: (fileName: string, content: string) => void;
let errorSpy: jasmine.Spy&((s: string) => void);
function writeConfig(tsconfig = '{"extends": "./tsconfig-base.json"}') {
write('tsconfig.json', tsconfig);
}
beforeEach(() => {
errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error);
const support = setup();
write = (fileName: string, content: string) => {
support.write(fileName, content);
};
basePath = support.basePath;
outDir = path.join(basePath, 'built');
write('tsconfig-base.json', `{
"compilerOptions": {
"experimentalDecorators": true,
"skipLibCheck": true,
"noImplicitAny": true,
"types": [],
"outDir": "built",
"rootDir": ".",
"baseUrl": ".",
"declaration": true,
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"lib": ["es6", "dom"],
"typeRoots": ["node_modules/@types"]
},
"angularCompilerOptions": {
"enableIvy": false
}
}`);
});
function writeSources() {
const welcomeMessage = `
Welcome
`;
write('src/basic.html', `
${welcomeMessage}
`);
write('src/comp1.ts', `
import {Component} from '@angular/core';
@Component({
selector: 'basic',
templateUrl: './basic.html',
})
export class BasicCmp1 {}`);
write('src/comp2.ts', `
import {Component} from '@angular/core';
@Component({
selector: 'basic2',
template: \`
${welcomeMessage}
\`,
})
export class BasicCmp2 {}
@Component({
selector: 'basic4',
template: \`${welcomeMessage}
\`,
})
export class BasicCmp4 {}`);
write('src/comp3.ts', `
import {Component} from '@angular/core';
@Component({
selector: 'basic3',
templateUrl: './basic.html',
})
export class BasicCmp3 {}`);
write('src/placeholders.html', `Name: {{
name // i18n(ph="name")
}}
`);
write('src/placeholder_cmp.ts', `
import {Component} from '@angular/core';
@Component({
selector: 'placeholders',
templateUrl: './placeholders.html',
})
export class PlaceholderCmp { name = 'whatever'; }`);
write('src/icu.html', `{
count, plural, =1 {book} other {books}
}
foo { count, plural, =1 {book} other {books} }
`);
write('src/icu_cmp.ts', `
import {Component} from '@angular/core';
@Component({
selector: 'icu',
templateUrl: './icu.html',
})
export class IcuCmp { count = 3; }`);
write('src/module.ts', `
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {BasicCmp1} from './comp1';
import {BasicCmp2, BasicCmp4} from './comp2';
import {BasicCmp3} from './comp3';
import {PlaceholderCmp} from './placeholder_cmp';
import {IcuCmp} from './icu_cmp';
@NgModule({
declarations: [
BasicCmp1,
BasicCmp2,
BasicCmp3,
BasicCmp4,
PlaceholderCmp,
IcuCmp,
],
imports: [CommonModule],
})
export class I18nModule {}
`);
}
it('should extract xmb', () => {
writeConfig();
writeSources();
const exitCode =
mainXi18n(['-p', basePath, '--i18nFormat=xmb', '--outFile=custom_file.xmb'], errorSpy);
expect(errorSpy).not.toHaveBeenCalled();
expect(exitCode).toBe(0);
const xmbOutput = path.join(outDir, 'custom_file.xmb');
expect(fs.existsSync(xmbOutput)).toBeTruthy();
const xmb = fs.readFileSync(xmbOutput, {encoding: 'utf-8'});
expect(xmb).toEqual(EXPECTED_XMB);
});
it('should extract xlf', () => {
writeConfig();
writeSources();
const exitCode = mainXi18n(['-p', basePath, '--i18nFormat=xlf', '--locale=fr'], errorSpy);
expect(errorSpy).not.toHaveBeenCalled();
expect(exitCode).toBe(0);
const xlfOutput = path.join(outDir, 'messages.xlf');
expect(fs.existsSync(xlfOutput)).toBeTruthy();
const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'});
expect(xlf).toEqual(EXPECTED_XLIFF);
});
it('should extract xlf2', () => {
writeConfig();
writeSources();
const exitCode =
mainXi18n(['-p', basePath, '--i18nFormat=xlf2', '--outFile=messages.xliff2.xlf'], errorSpy);
expect(errorSpy).not.toHaveBeenCalled();
expect(exitCode).toBe(0);
const xlfOutput = path.join(outDir, 'messages.xliff2.xlf');
expect(fs.existsSync(xlfOutput)).toBeTruthy();
const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'});
expect(xlf).toEqual(EXPECTED_XLIFF2);
});
it('should not emit js', () => {
writeConfig();
writeSources();
const exitCode =
mainXi18n(['-p', basePath, '--i18nFormat=xlf2', '--outFile=messages.xliff2.xlf'], errorSpy);
expect(errorSpy).not.toHaveBeenCalled();
expect(exitCode).toBe(0);
const moduleOutput = path.join(outDir, 'src', 'module.js');
expect(fs.existsSync(moduleOutput)).toBeFalsy();
});
});