Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
619b3c56ea | ||
|
5e0da552b0 | ||
|
5f2eb2a7a0 | ||
|
90b59793a7 | ||
|
deb6b2373b | ||
|
17dec7deb8 | ||
|
71f4f42b33 | ||
|
73f39d625c | ||
|
3bf2aaca4e |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,2 +1,2 @@
|
|||||||
github: #biesbjerg
|
github: biesbjerg
|
||||||
custom: https://donate.biesbjerg.com
|
custom: https://donate.biesbjerg.com
|
||||||
|
@@ -15,7 +15,8 @@ Add a script to your project's `package.json`:
|
|||||||
```json
|
```json
|
||||||
...
|
...
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"extract-i18n": "ngx-translate-extract --input ./src --output ./src/assets/i18n/strings.json --key-as-default-value --clean --sort --format namespaced-json"
|
"i18n:init": "ngx-translate-extract --input ./src --output ./src/assets/i18n/template.json --key-as-default-value --replace --format json",
|
||||||
|
"i18n:extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/{en,da,de,fi,nb,nl,sv}.json --clean --format json"
|
||||||
}
|
}
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
@@ -100,3 +101,7 @@ Examples:
|
|||||||
ngx-translate-extract -i './src/**/*.{ts,tsx,html}' -o strings.json Extract from ts, tsx and html
|
ngx-translate-extract -i './src/**/*.{ts,tsx,html}' -o strings.json Extract from ts, tsx and html
|
||||||
ngx-translate-extract -i './src/**/!(*.spec).{ts,html}' -o Extract from ts, html, excluding files with ".spec"
|
ngx-translate-extract -i './src/**/!(*.spec).{ts,html}' -o Extract from ts, html, excluding files with ".spec"
|
||||||
strings.json
|
strings.json
|
||||||
|
|
||||||
|
## Note for GetText users
|
||||||
|
|
||||||
|
Please pay attention of which version of `gettext-parser` you actually use in your project. For instance, `gettext-parser:1.2.2` does not support HTML tags in translation keys.
|
21
package-lock.json
generated
21
package-lock.json
generated
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "@biesbjerg/ngx-translate-extract",
|
"name": "@biesbjerg/ngx-translate-extract",
|
||||||
"version": "6.0.0",
|
"version": "6.0.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/compiler": {
|
"@angular/compiler": {
|
||||||
"version": "9.0.7",
|
"version": "9.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.1.tgz",
|
||||||
"integrity": "sha512-hFpkuGpzxpK5h59LHHAjTFWsY6DCXZwgJFqvCuTPxWi/srvLGZRXrpC6Z1SlgHI9xxXaPfoa4uWw2VfA3BnqEg=="
|
"integrity": "sha512-u1IP6IzUgK6lIzrG1cxp96umXgtThyhuFn/KPoyVt7wPxZ6vVR0ZxjM7zycEcrMGzk0nf0nyOKaksJk9sTXTbg==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
"version": "7.8.3",
|
"version": "7.8.3",
|
||||||
@@ -136,6 +137,15 @@
|
|||||||
"integrity": "sha512-GcgAp7RXXGmA61spVEKZYpIy3/iV6GHbTW9f9kaKwHVQgnWitt6X026e+3N6j8ep1bkIWj83qPHQ3Y9Ft8FqiQ==",
|
"integrity": "sha512-GcgAp7RXXGmA61spVEKZYpIy3/iV6GHbTW9f9kaKwHVQgnWitt6X026e+3N6j8ep1bkIWj83qPHQ3Y9Ft8FqiQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/gettext-parser": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/gettext-parser/-/gettext-parser-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-I/wvhr+l5M7IwBF1ADBfNQ6qGfUg85UTjj/AZWn09Y+POqyLe1cfbdJSMWzCobiJ3EJNY23MQCbP6jxQT81OTQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/glob": {
|
"@types/glob": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
|
||||||
@@ -2437,7 +2447,8 @@
|
|||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.8.3",
|
"version": "3.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w=="
|
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"util": {
|
"util": {
|
||||||
"version": "0.10.4",
|
"version": "0.10.4",
|
||||||
|
13
package.json
13
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biesbjerg/ngx-translate-extract",
|
"name": "@biesbjerg/ngx-translate-extract",
|
||||||
"version": "6.0.3",
|
"version": "6.0.4",
|
||||||
"description": "Extract strings from projects using ngx-translate",
|
"description": "Extract strings from projects using ngx-translate",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
@@ -61,9 +61,11 @@
|
|||||||
},
|
},
|
||||||
"config": {},
|
"config": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@angular/compiler": "^9.1.1",
|
||||||
"@types/braces": "^3.0.0",
|
"@types/braces": "^3.0.0",
|
||||||
"@types/chai": "^4.2.11",
|
"@types/chai": "^4.2.11",
|
||||||
"@types/flat": "^5.0.0",
|
"@types/flat": "^5.0.0",
|
||||||
|
"@types/gettext-parser": "4.0.0",
|
||||||
"@types/glob": "^7.1.1",
|
"@types/glob": "^7.1.1",
|
||||||
"@types/mkdirp": "^1.0.0",
|
"@types/mkdirp": "^1.0.0",
|
||||||
"@types/mocha": "^7.0.2",
|
"@types/mocha": "^7.0.2",
|
||||||
@@ -80,10 +82,14 @@
|
|||||||
"tslint": "^6.1.0",
|
"tslint": "^6.1.0",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
"tslint-eslint-rules": "^5.4.0",
|
"tslint-eslint-rules": "^5.4.0",
|
||||||
"tslint-etc": "^1.10.1"
|
"tslint-etc": "^1.10.1",
|
||||||
|
"typescript": "^3.8.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/compiler": "^8.0.0 || ^9.0.0",
|
||||||
|
"typescript": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/compiler": "^9.0.7",
|
|
||||||
"@phenomnomnominal/tsquery": "^4.0.0",
|
"@phenomnomnominal/tsquery": "^4.0.0",
|
||||||
"boxen": "^4.2.0",
|
"boxen": "^4.2.0",
|
||||||
"colorette": "^1.1.0",
|
"colorette": "^1.1.0",
|
||||||
@@ -93,7 +99,6 @@
|
|||||||
"mkdirp": "^1.0.3",
|
"mkdirp": "^1.0.3",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"terminal-link": "^2.1.1",
|
"terminal-link": "^2.1.1",
|
||||||
"typescript": "^3.8.3",
|
|
||||||
"yargs": "^15.3.1"
|
"yargs": "^15.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { CompilerInterface } from './compiler.interface';
|
import { CompilerInterface } from './compiler.interface';
|
||||||
import { TranslationCollection, TranslationType } from '../utils/translation.collection';
|
import { TranslationCollection, TranslationType } from '../utils/translation.collection';
|
||||||
|
|
||||||
import * as gettext from 'gettext-parser';
|
import { po } from 'gettext-parser';
|
||||||
|
|
||||||
export class PoCompiler implements CompilerInterface {
|
export class PoCompiler implements CompilerInterface {
|
||||||
public extension: string = 'po';
|
public extension: string = 'po';
|
||||||
@@ -34,23 +34,24 @@ export class PoCompiler implements CompilerInterface {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return gettext.po.compile(data);
|
return po.compile(data).toString('utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
public parse(contents: string): TranslationCollection {
|
public parse(contents: string): TranslationCollection {
|
||||||
const collection = new TranslationCollection();
|
const collection = new TranslationCollection();
|
||||||
|
|
||||||
const po = gettext.po.parse(contents, 'utf8');
|
const parsedPo = po.parse(contents, 'utf8');
|
||||||
if (!po.translations.hasOwnProperty(this.domain)) {
|
|
||||||
|
if (!parsedPo.translations.hasOwnProperty(this.domain)) {
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = Object.keys(po.translations[this.domain])
|
const values = Object.keys(parsedPo.translations[this.domain])
|
||||||
.filter((key) => key.length > 0)
|
.filter((key) => key.length > 0)
|
||||||
.reduce((result, key) => {
|
.reduce((result, key) => {
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
[key]: po.translations[this.domain][key].msgstr.pop()
|
[key]: parsedPo.translations[this.domain][key].msgstr.pop()
|
||||||
};
|
};
|
||||||
}, {} as TranslationType);
|
}, {} as TranslationType);
|
||||||
|
|
||||||
|
1
src/declarations.d.ts
vendored
1
src/declarations.d.ts
vendored
@@ -1 +0,0 @@
|
|||||||
declare module 'gettext-parser';
|
|
@@ -82,6 +82,6 @@ export class DirectiveParser implements ParserInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected cleanKey(val: string): string {
|
protected cleanKey(val: string): string {
|
||||||
return val.replace(/\r?\n|\r|\t/g, '');
|
return val.replace(/\r?\n|\r|\t/g, '').trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,16 @@
|
|||||||
import { TmplAstNode, parseTemplate, BindingPipe, LiteralPrimitive, Conditional, TmplAstTextAttribute } from '@angular/compiler';
|
import {
|
||||||
|
AST,
|
||||||
|
TmplAstNode,
|
||||||
|
parseTemplate,
|
||||||
|
BindingPipe,
|
||||||
|
LiteralPrimitive,
|
||||||
|
Conditional,
|
||||||
|
TmplAstTextAttribute,
|
||||||
|
Binary,
|
||||||
|
LiteralMap,
|
||||||
|
LiteralArray,
|
||||||
|
Interpolation
|
||||||
|
} from '@angular/compiler';
|
||||||
|
|
||||||
import { ParserInterface } from './parser.interface';
|
import { ParserInterface } from './parser.interface';
|
||||||
import { TranslationCollection } from '../utils/translation.collection';
|
import { TranslationCollection } from '../utils/translation.collection';
|
||||||
@@ -36,9 +48,8 @@ export class PipeParser implements ParserInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node?.value?.ast?.expressions) {
|
if (node?.value?.ast) {
|
||||||
const translateables = node.value.ast.expressions.filter((exp: any) => this.expressionIsOrHasBindingPipe(exp));
|
ret.push(...this.getTranslatablesFromAst(node.value.ast));
|
||||||
ret.push(...translateables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node?.attributes) {
|
if (node?.attributes) {
|
||||||
@@ -51,17 +62,8 @@ export class PipeParser implements ParserInterface {
|
|||||||
if (node?.inputs) {
|
if (node?.inputs) {
|
||||||
node.inputs.forEach((input: any) => {
|
node.inputs.forEach((input: any) => {
|
||||||
// <element [attrib]="'identifier' | translate">
|
// <element [attrib]="'identifier' | translate">
|
||||||
if (input?.value?.ast && this.expressionIsOrHasBindingPipe(input.value.ast)) {
|
if (input?.value?.ast) {
|
||||||
ret.push(input.value.ast);
|
ret.push(...this.getTranslatablesFromAst(input.value.ast));
|
||||||
}
|
|
||||||
|
|
||||||
// <element attrib="{{'identifier' | translate}}>"
|
|
||||||
if (input?.value?.ast?.expressions) {
|
|
||||||
input.value.ast.expressions.forEach((exp: BindingPipe) => {
|
|
||||||
if (this.expressionIsOrHasBindingPipe(exp)) {
|
|
||||||
ret.push(exp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,63 @@ export class PipeParser implements ParserInterface {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected expressionIsOrHasBindingPipe(exp: any): boolean {
|
protected getTranslatablesFromAst(ast: AST): BindingPipe[] {
|
||||||
|
// the entire expression is the translate pipe, e.g.:
|
||||||
|
// - 'foo' | translate
|
||||||
|
// - (condition ? 'foo' : 'bar') | translate
|
||||||
|
if (this.expressionIsOrHasBindingPipe(ast)) {
|
||||||
|
return [ast];
|
||||||
|
}
|
||||||
|
|
||||||
|
// angular double curly bracket interpolation, e.g.:
|
||||||
|
// - {{ expressions }}
|
||||||
|
if (ast instanceof Interpolation) {
|
||||||
|
return this.getTranslatablesFromAsts(ast.expressions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ternary operator, e.g.:
|
||||||
|
// - condition ? null : ('foo' | translate)
|
||||||
|
// - condition ? ('foo' | translate) : null
|
||||||
|
if (ast instanceof Conditional) {
|
||||||
|
return this.getTranslatablesFromAsts([ast.trueExp, ast.falseExp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// string concatenation, e.g.:
|
||||||
|
// - 'foo' + 'bar' + ('baz' | translate)
|
||||||
|
if (ast instanceof Binary) {
|
||||||
|
return this.getTranslatablesFromAsts([ast.left, ast.right]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// a pipe on the outer expression, but not the translate pipe - ignore the pipe, visit the expression, e.g.:
|
||||||
|
// - { foo: 'Hello' | translate } | json
|
||||||
|
if (ast instanceof BindingPipe) {
|
||||||
|
return this.getTranslatablesFromAst(ast.exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// object - ignore the keys, visit all values, e.g.:
|
||||||
|
// - { key1: 'value1' | translate, key2: 'value2' | translate }
|
||||||
|
if (ast instanceof LiteralMap) {
|
||||||
|
return this.getTranslatablesFromAsts(ast.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
// array - visit all its values, e.g.:
|
||||||
|
// - [ 'value1' | translate, 'value2' | translate ]
|
||||||
|
if (ast instanceof LiteralArray) {
|
||||||
|
return this.getTranslatablesFromAsts(ast.expressions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getTranslatablesFromAsts(asts: AST[]): BindingPipe[] {
|
||||||
|
return this.flatten(asts.map(ast => this.getTranslatablesFromAst(ast)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected flatten<T extends AST>(array: T[][]): T[] {
|
||||||
|
return [].concat(...array);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected expressionIsOrHasBindingPipe(exp: any): exp is BindingPipe {
|
||||||
if (exp.name && exp.name === TRANSLATE_PIPE_NAME) {
|
if (exp.name && exp.name === TRANSLATE_PIPE_NAME) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
24
tests/compilers/po.compiler.spec.ts
Normal file
24
tests/compilers/po.compiler.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { expect } from 'chai';
|
||||||
|
|
||||||
|
import { TranslationCollection } from '../../src/utils/translation.collection';
|
||||||
|
import { PoCompiler } from '../../src/compilers/po.compiler';
|
||||||
|
|
||||||
|
describe('PoCompiler', () => {
|
||||||
|
let compiler: PoCompiler;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
compiler = new PoCompiler();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should still include html ', () => {
|
||||||
|
const collection = new TranslationCollection({
|
||||||
|
'A <strong>test</strong>': 'Un <strong>test</strong>',
|
||||||
|
'With a lot of <em>html</em> included': 'Avec beaucoup d\'<em>html</em> inclus'
|
||||||
|
});
|
||||||
|
const result: Buffer = Buffer.from(compiler.compile(collection));
|
||||||
|
expect(result.toString('utf8')).to.equal('msgid ""\nmsgstr ""\n"mime-version: 1.0\\n"\n"Content-Type: text/plain; charset=utf-8\\n"\n"Content-Transfer-Encoding: 8bit\\n"\n\nmsgid "A <strong>test</strong>"\nmsgstr "Un <strong>test</strong>"\n\nmsgid "With a lot of <em>html</em> included"\nmsgstr "Avec beaucoup d\'<em>html</em> inclus"');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -36,6 +36,12 @@ describe('DirectiveParser', () => {
|
|||||||
expect(keys).to.deep.equal(['Hello <strong translate>World</strong>']);
|
expect(keys).to.deep.equal(['Hello <strong translate>World</strong>']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not exclude html tags in children', () => {
|
||||||
|
const contents = `<div translate>Hello <strong>World</strong></div>`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['Hello <strong>World</strong>']);
|
||||||
|
});
|
||||||
|
|
||||||
it('should extract and parse inline template', () => {
|
it('should extract and parse inline template', () => {
|
||||||
const contents = `
|
const contents = `
|
||||||
@Component({
|
@Component({
|
||||||
@@ -117,4 +123,22 @@ describe('DirectiveParser', () => {
|
|||||||
const keys = parser.extract(contents, templateFilename).keys();
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
expect(keys).to.deep.equal(['client.search.searchBtn']);
|
expect(keys).to.deep.equal(['client.search.searchBtn']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should extract contents without indent spaces and trim leading/trailing whitespace', () => {
|
||||||
|
const contents = `
|
||||||
|
<div translate>
|
||||||
|
this is an example
|
||||||
|
of a long label
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p translate>
|
||||||
|
this is an example
|
||||||
|
of a long label
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['this is an example of a long label']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -36,6 +36,17 @@ describe('MarkerParser', () => {
|
|||||||
expect(keys).to.deep.equal(['Hello world', 'This is a very very very very long line.', 'Mix of different types']);
|
expect(keys).to.deep.equal(['Hello world', 'This is a very very very very long line.', 'Mix of different types']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should extract split strings while keeping html tags', () => {
|
||||||
|
const contents = `
|
||||||
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
|
_('Hello ' + 'world');
|
||||||
|
_('This <em>is</em> a ' + 'very ' + 'very ' + 'very ' + 'very ' + 'long line.');
|
||||||
|
_('Mix ' + \`of \` + 'different ' + \`types\`);
|
||||||
|
`;
|
||||||
|
const keys = parser.extract(contents, componentFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['Hello world', 'This <em>is</em> a very very very very long line.', 'Mix of different types']);
|
||||||
|
});
|
||||||
|
|
||||||
it('should extract the strings', () => {
|
it('should extract the strings', () => {
|
||||||
const contents = `
|
const contents = `
|
||||||
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
|
@@ -47,12 +47,48 @@ describe('PipeParser', () => {
|
|||||||
expect(keys).to.deep.equal(['Hello', 'World']);
|
expect(keys).to.deep.equal(['Hello', 'World']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should extract strings from ternary operators right expression', () => {
|
||||||
|
const contents = `{{ condition ? null : ('World' | translate) }}`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['World']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract strings from ternary operators inside attribute bindings', () => {
|
||||||
|
const contents = `<span [attr]="condition ? null : ('World' | translate)"></span>`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['World']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract strings from ternary operators left expression', () => {
|
||||||
|
const contents = `{{ condition ? ('World' | translate) : null }}`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['World']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract strings inside string concatenation', () => {
|
||||||
|
const contents = `{{ 'a' + ('Hello' | translate) + 'b' + 'c' + ('World' | translate) + 'd' }}`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['Hello', 'World']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract strings from object', () => {
|
||||||
|
const contents = `{{ { foo: 'Hello' | translate, bar: ['World' | translate], deep: { nested: { baz: 'Yes' | translate } } } | json }}`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['Hello', 'World', 'Yes']);
|
||||||
|
});
|
||||||
|
|
||||||
it('should extract strings from ternary operators inside attribute bindings', () => {
|
it('should extract strings from ternary operators inside attribute bindings', () => {
|
||||||
const contents = `<span [attr]="(condition ? 'Hello' : 'World') | translate"></span>`;
|
const contents = `<span [attr]="(condition ? 'Hello' : 'World') | translate"></span>`;
|
||||||
const keys = parser.extract(contents, templateFilename).keys();
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
expect(keys).to.deep.equal(['Hello', 'World']);
|
expect(keys).to.deep.equal(['Hello', 'World']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should extract strings from nested expressions', () => {
|
||||||
|
const contents = `<span [attr]="{ foo: ['a' + ((condition ? 'Hello' : 'World') | translate) + 'b'] }"></span>`;
|
||||||
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
expect(keys).to.deep.equal(['Hello', 'World']);
|
||||||
|
});
|
||||||
|
|
||||||
it('should extract strings from nested ternary operators ', () => {
|
it('should extract strings from nested ternary operators ', () => {
|
||||||
const contents = `<h3>{{ (condition ? 'Hello' : anotherCondition ? 'Nested' : 'World' ) | translate }}</h3>`;
|
const contents = `<h3>{{ (condition ? 'Hello' : anotherCondition ? 'Nested' : 'World' ) | translate }}</h3>`;
|
||||||
const keys = parser.extract(contents, templateFilename).keys();
|
const keys = parser.extract(contents, templateFilename).keys();
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noImplicitThis": true,
|
"noImplicitThis": true,
|
||||||
|
@@ -112,6 +112,7 @@
|
|||||||
"check-operator",
|
"check-operator",
|
||||||
"check-separator",
|
"check-separator",
|
||||||
"check-type"
|
"check-type"
|
||||||
]
|
],
|
||||||
|
"quotemark": [true, "single"]
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user