Add tests and allow more liberal spacing with get/instant calls

This commit is contained in:
Kim Biesbjerg 2016-12-13 15:17:03 +01:00
parent ca8b122295
commit 8093370e94
9 changed files with 64 additions and 20 deletions

View File

@ -21,7 +21,7 @@ const options = cli.parse({
[options.dir, options.output].forEach(dir => { [options.dir, options.output].forEach(dir => {
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
cli.fatal('The directory path you supplied was not found: ' + dir); cli.fatal(`The directory path you supplied was not found: '${dir}'`);
} }
}); });
@ -39,17 +39,12 @@ const patterns: string[] = [
'/**/*.js' '/**/*.js'
]; ];
const extractor: Extractor = new Extractor(parsers, patterns);
try { try {
const extractor: Extractor = new Extractor(parsers, patterns);
cli.info(`Extracting strings from '${options.dir}'`); cli.info(`Extracting strings from '${options.dir}'`);
const extracted: TranslationCollection = extractor.process(options.dir); const extracted: TranslationCollection = extractor.process(options.dir);
cli.ok(`* Extracted ${extracted.count()} strings`); cli.ok(`* Extracted ${extracted.count()} strings`);
if (extracted.isEmpty()) {
process.exit();
}
let collection: TranslationCollection = extracted; let collection: TranslationCollection = extracted;
let compiler = new JsonCompiler(); let compiler = new JsonCompiler();
@ -60,8 +55,10 @@ try {
if (!options.replace && fs.existsSync(dest)) { if (!options.replace && fs.existsSync(dest)) {
const existing: TranslationCollection = compiler.parse(fs.readFileSync(dest, 'utf-8')); const existing: TranslationCollection = compiler.parse(fs.readFileSync(dest, 'utf-8'));
collection = extracted.union(existing); if (existing.count() > 0) {
cli.ok(`* Merged ${existing.count()} existing strings`); collection = extracted.union(existing);
cli.ok(`* Merged ${existing.count()} existing strings`);
}
if (options.clean) { if (options.clean) {
const collectionCount = collection.count(); const collectionCount = collection.count();

View File

@ -25,7 +25,7 @@ export class PoCompiler implements CompilerInterface {
msgstr: collection.get(key) msgstr: collection.get(key)
}; };
return translations; return translations;
}, <any>{}) }, <any> {})
} }
}; };
@ -45,7 +45,7 @@ export class PoCompiler implements CompilerInterface {
.reduce((values, key) => { .reduce((values, key) => {
values[key] = po.translations[this.domain][key].msgstr.pop(); values[key] = po.translations[this.domain][key].msgstr.pop();
return values; return values;
}, <TranslationType>{}); }, <TranslationType> {});
return new TranslationCollection(values); return new TranslationCollection(values);
} }

View File

@ -12,7 +12,7 @@ export abstract class AbstractTemplateParser {
* Extracts inline template from components * Extracts inline template from components
*/ */
protected _extractInlineTemplate(contents: string): string { protected _extractInlineTemplate(contents: string): string {
const match = new RegExp(/template\s*:\s*(["'`])((.|[\r\n])+?[^\\])\1/).exec(contents); const match = new RegExp(/template\s*:\s*(["'`])([^\1]*?)\1/).exec(contents);
if (match !== null) { if (match !== null) {
return match[2]; return match[2];
} }

View File

@ -15,7 +15,7 @@ export class PipeParser extends AbstractTemplateParser implements ParserInterfac
protected _parseTemplate(template: string): TranslationCollection { protected _parseTemplate(template: string): TranslationCollection {
let collection: TranslationCollection = new TranslationCollection(); let collection: TranslationCollection = new TranslationCollection();
const regExp = new RegExp(/(['"`])([^\1\r\n]*)\1\s*\|\s*translate(:.*?)?/, 'g'); const regExp = new RegExp(/(['"`])([^\1]*)\1\s*\|\s*translate/, 'g');
let matches: RegExpExecArray; let matches: RegExpExecArray;
while (matches = regExp.exec(template)) { while (matches = regExp.exec(template)) {

View File

@ -11,10 +11,10 @@ export class ServiceParser implements ParserInterface {
return collection; return collection;
} }
const methodRegExp: RegExp = new RegExp(/(?:get|instant)\s*\(\s*(\[?(['"`])([^\1\r\n]+)\2\]?)/); const methodRegExp: RegExp = new RegExp(/(?:get|instant)\s*\(\s*(\[?\s*(['"`])([^\1\r\n]*)\2\s*\]?)/);
const regExp: RegExp = new RegExp(`${translateServiceVar}\.${methodRegExp.source}`, 'g'); const regExp: RegExp = new RegExp(`${translateServiceVar}\.${methodRegExp.source}`, 'g');
let matches; let matches: RegExpExecArray;
while (matches = regExp.exec(contents)) { while (matches = regExp.exec(contents)) {
if (this._stringContainsArray(matches[1])) { if (this._stringContainsArray(matches[1])) {
collection = collection.addKeys(this._stringToArray(matches[1])); collection = collection.addKeys(this._stringToArray(matches[1]));

View File

@ -18,7 +18,7 @@ export class TranslationCollection {
const values = keys.reduce((results, key) => { const values = keys.reduce((results, key) => {
results[key] = ''; results[key] = '';
return results; return results;
}, <TranslationType>{}); }, <TranslationType> {});
return new TranslationCollection(Object.assign({}, this.values, values)); return new TranslationCollection(Object.assign({}, this.values, values));
} }

View File

@ -41,6 +41,12 @@ describe('AbstractTemplateParser', () => {
expect(result).to.equal(false); expect(result).to.equal(false);
}); });
it('should normalize bound attributes', () => {
const contents = `<p [translate]="'KEY'">Hello World</p>`;
const template = parser.normalizeTemplateAttributes(contents);
expect(template).to.equal('<p translate="KEY">Hello World</p>');
});
it('should extract inline template', () => { it('should extract inline template', () => {
const contents = ` const contents = `
@Component({ @Component({
@ -53,10 +59,25 @@ describe('AbstractTemplateParser', () => {
expect(template).to.equal('<p translate>Hello World</p>'); expect(template).to.equal('<p translate>Hello World</p>');
}); });
it('should normalize bound attributes', () => { it('should extract inline template spanning multiple lines', () => {
const contents = `<p [translate]="'KEY'">Hello World</p>`; const contents = `
const template = parser.normalizeTemplateAttributes(contents); @Component({
expect(template).to.equal('<p translate="KEY">Hello World</p>'); selector: 'test',
template: '
<p>
Hello World
</p>
',
styles: ['
p {
color: red;
}
']
})
export class TestComponent { }
`;
const template = parser.extractInlineTemplate(contents);
expect(template).to.equal('\n\t\t\t\t\t<p>\n\t\t\t\t\t\tHello World\n\t\t\t\t\t</p>\n\t\t\t\t');
}); });
}); });

View File

@ -18,6 +18,12 @@ describe('PipeParser', () => {
expect(keys).to.deep.equal(['World']); expect(keys).to.deep.equal(['World']);
}); });
it('should extract strings with escaped quotes', () => {
const contents = `Hello {{ 'World\'s largest potato' | translate }}`;
const keys = parser.extract(contents, templateFilename).keys();
expect(keys).to.deep.equal([`World's largest potato`]);
});
it('should extract interpolated strings using translate pipe in attributes', () => { it('should extract interpolated strings using translate pipe in attributes', () => {
const contents = `<span attr="{{ 'Hello World' | translate }}"></span>`; const contents = `<span attr="{{ 'Hello World' | translate }}"></span>`;
const keys = parser.extract(contents, templateFilename).keys(); const keys = parser.extract(contents, templateFilename).keys();

View File

@ -103,4 +103,24 @@ describe('ServiceParser', () => {
expect(keys).to.deep.equal([]); expect(keys).to.deep.equal([]);
}); });
it('should extract strings with liberal spacing', () => {
const contents = `
@Component({ })
export class AppComponent {
public constructor(
protected _translateService: TranslateService,
protected _otherService: OtherService
) { }
public test() {
this._translateService.instant('Hello');
this._translateService.get ( 'World' );
this._translateService.instant ( ['How'] );
this._translateService.get([ 'Are' ]);
this._translateService.get([ 'You' , 'Today' ]);
}
`;
const keys = parser.extract(contents, componentFilename).keys();
expect(keys).to.deep.equal(['Hello', 'World', 'How', 'Are', 'You', 'Today']);
});
}); });