Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8fd157802b | ||
|
1db4794ee9 | ||
|
1eb1d0092d | ||
|
4d3a3529b8 | ||
|
97e8937709 | ||
|
eb7f3f603e | ||
|
ab2b78eaec | ||
|
75ee2bdfda |
33
README.md
33
README.md
@@ -78,7 +78,7 @@ _('Extract me');
|
||||
`ngx-translate-extract ... -m _`
|
||||
|
||||
## Commandline arguments
|
||||
```shell
|
||||
```
|
||||
Usage:
|
||||
ngx-translate-extract [options]
|
||||
|
||||
@@ -89,19 +89,22 @@ Options:
|
||||
can use path expansion, glob patterns and multiple
|
||||
paths
|
||||
[array] [default: current working path]
|
||||
--patterns, -p Extract strings from the following file patterns
|
||||
[array] [required] [default: current working path]
|
||||
--patterns, -p Extract strings from the following file patterns
|
||||
[array] [default: ["/**/*.html","/**/*.ts"]]
|
||||
--output, -o Paths where you would like to save extracted
|
||||
strings. You can use path expansion, glob patterns
|
||||
and multiple paths [array] [required]
|
||||
--format, -f Output format
|
||||
--output, -o Paths where you would like to save extracted
|
||||
strings. You can use path expansion, glob
|
||||
patterns and multiple paths [array] [required]
|
||||
--format, -f Output format
|
||||
[string] [choices: "json", "namespaced-json", "pot"] [default: "json"]
|
||||
--format-indentation, --fi Output format indentation [string] [default: " "]
|
||||
--replace, -r Replace the contents of output file if it exists
|
||||
(Merges by default) [boolean] [default: false]
|
||||
--sort, -s Sort strings in alphabetical order when saving
|
||||
[boolean] [default: false]
|
||||
--clean, -c Remove obsolete strings when merging
|
||||
[boolean] [default: false]
|
||||
--key-as-default-value, -k Use key as default value for translations
|
||||
[boolean] [default: false]
|
||||
--format-indentation, --fi Output format indentation [string] [default: " "]
|
||||
--replace, -r Replace the contents of output file if it exists
|
||||
(Merges by default) [boolean]
|
||||
--sort, -s Sort strings in alphabetical order when saving
|
||||
[boolean]
|
||||
--clean, -c Remove obsolete strings when merging [boolean]
|
||||
--key-as-default-value, -k Use key as default value for translations
|
||||
[boolean]
|
||||
--null-as-default-value, -n Use null as default value for translations
|
||||
[boolean]
|
||||
```
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@biesbjerg/ngx-translate-extract",
|
||||
"version": "4.0.0",
|
||||
"version": "4.2.0",
|
||||
"description": "Extract strings from projects using ngx-translate",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
|
@@ -10,6 +10,7 @@ import { MarkerParser } from '../parsers/marker.parser';
|
||||
import { PostProcessorInterface } from '../post-processors/post-processor.interface';
|
||||
import { SortByKeyPostProcessor } from '../post-processors/sort-by-key.post-processor';
|
||||
import { KeyAsDefaultValuePostProcessor } from '../post-processors/key-as-default-value.post-processor';
|
||||
import { NullAsDefaultValuePostProcessor } from '../post-processors/null-as-default-value.post-processor';
|
||||
import { PurgeObsoleteKeysPostProcessor } from '../post-processors/purge-obsolete-keys.post-processor';
|
||||
import { CompilerInterface } from '../compilers/compiler.interface';
|
||||
import { CompilerFactory } from '../compilers/compiler.factory';
|
||||
@@ -24,12 +25,13 @@ export const cli = yargs
|
||||
.option('input', {
|
||||
alias: 'i',
|
||||
describe: 'Paths you would like to extract strings from. You can use path expansion, glob patterns and multiple paths',
|
||||
default: process.env.PWD,
|
||||
default: [process.env.PWD],
|
||||
type: 'array',
|
||||
normalize: true
|
||||
normalize: true,
|
||||
required: true
|
||||
})
|
||||
.check(options => {
|
||||
(options.input as unknown as string[]).forEach((dir: string) => {
|
||||
options.input.forEach((dir: string) => {
|
||||
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
||||
throw new Error(`The path you supplied was not found: '${dir}'`);
|
||||
}
|
||||
@@ -66,31 +68,33 @@ export const cli = yargs
|
||||
.option('replace', {
|
||||
alias: 'r',
|
||||
describe: 'Replace the contents of output file if it exists (Merges by default)',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('sort', {
|
||||
alias: 's',
|
||||
describe: 'Sort strings in alphabetical order when saving',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('clean', {
|
||||
alias: 'c',
|
||||
describe: 'Remove obsolete strings when merging',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('key-as-default-value', {
|
||||
alias: 'k',
|
||||
describe: 'Use key as default value for translations',
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
})
|
||||
.option('null-as-default-value', {
|
||||
alias: 'n',
|
||||
describe: 'Use null as default value for translations',
|
||||
type: 'boolean'
|
||||
})
|
||||
.conflicts('key-as-default-value', 'null-as-default-value')
|
||||
.exitProcess(true)
|
||||
.parse(process.argv);
|
||||
|
||||
const extractTask = new ExtractTask(cli.input as unknown as string[], cli.output, {
|
||||
const extractTask = new ExtractTask(cli.input, cli.output, {
|
||||
replace: cli.replace,
|
||||
patterns: cli.patterns
|
||||
});
|
||||
@@ -111,6 +115,8 @@ if (cli.clean) {
|
||||
}
|
||||
if (cli.keyAsDefaultValue) {
|
||||
postProcessors.push(new KeyAsDefaultValuePostProcessor());
|
||||
} else if (cli.nullAsDefaultValue) {
|
||||
postProcessors.push(new NullAsDefaultValuePostProcessor());
|
||||
}
|
||||
if (cli.sort) {
|
||||
postProcessors.push(new SortByKeyPostProcessor());
|
||||
|
@@ -9,7 +9,7 @@ const MARKER_PACKAGE_IMPORT_NAME = 'marker';
|
||||
|
||||
export class MarkerParser implements ParserInterface {
|
||||
|
||||
public extract(contents: string, filePath: string): TranslationCollection {
|
||||
public extract(contents: string, filePath: string): TranslationCollection | null {
|
||||
const sourceFile = tsquery.ast(contents, filePath);
|
||||
|
||||
const markerFnName = getNamedImportAlias(sourceFile, MARKER_PACKAGE_MODULE_NAME, MARKER_PACKAGE_IMPORT_NAME);
|
||||
|
@@ -2,6 +2,6 @@ import { TranslationCollection } from '../utils/translation.collection';
|
||||
|
||||
export interface ParserInterface {
|
||||
|
||||
extract(template: string, path: string): TranslationCollection;
|
||||
extract(source: string, filePath: string): TranslationCollection | null;
|
||||
|
||||
}
|
||||
|
@@ -2,14 +2,14 @@ import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
|
||||
import { ParserInterface } from './parser.interface';
|
||||
import { TranslationCollection } from '../utils/translation.collection';
|
||||
import { findClasses, findClassPropertyByType, findMethodCallExpression, getStringsFromExpression } from '../utils/ast-helpers';
|
||||
import { findClasses, findClassPropertyByType, findMethodCallExpressions, getStringsFromExpression } from '../utils/ast-helpers';
|
||||
|
||||
const TRANSLATE_SERVICE_TYPE_REFERENCE = 'TranslateService';
|
||||
const TRANSLATE_SERVICE_METHOD_NAMES = ['get', 'instant', 'stream'];
|
||||
|
||||
export class ServiceParser implements ParserInterface {
|
||||
|
||||
public extract(source: string, filePath: string): TranslationCollection {
|
||||
public extract(source: string, filePath: string): TranslationCollection | null {
|
||||
const sourceFile = tsquery.ast(source, filePath);
|
||||
|
||||
const classNodes = findClasses(sourceFile);
|
||||
@@ -25,7 +25,7 @@ export class ServiceParser implements ParserInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
const callNodes = findMethodCallExpression(classNode, propName, TRANSLATE_SERVICE_METHOD_NAMES);
|
||||
const callNodes = findMethodCallExpressions(classNode, propName, TRANSLATE_SERVICE_METHOD_NAMES);
|
||||
callNodes.forEach(callNode => {
|
||||
const [firstArgNode] = callNode.arguments;
|
||||
if (!firstArgNode) {
|
||||
|
12
src/post-processors/null-as-default-value.post-processor.ts
Normal file
12
src/post-processors/null-as-default-value.post-processor.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { TranslationCollection } from '../utils/translation.collection';
|
||||
import { PostProcessorInterface } from './post-processor.interface';
|
||||
|
||||
export class NullAsDefaultValuePostProcessor implements PostProcessorInterface {
|
||||
|
||||
public name: string = 'NullAsDefaultValue';
|
||||
|
||||
public process(draft: TranslationCollection, extracted: TranslationCollection, existing: TranslationCollection): TranslationCollection {
|
||||
return draft.map((key, val) => existing.get(key) === undefined ? null : val);
|
||||
}
|
||||
|
||||
}
|
@@ -72,7 +72,7 @@ export function findFunctionCallExpressions(node: Node, fnName: string | string[
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function findMethodCallExpression(node: Node, prop: string, fnName: string | string[]): CallExpression[] {
|
||||
export function findMethodCallExpressions(node: Node, prop: string, fnName: string | string[]): CallExpression[] {
|
||||
if (Array.isArray(fnName)) {
|
||||
fnName = fnName.join('|');
|
||||
}
|
||||
|
@@ -27,4 +27,19 @@ describe('MarkerParser', () => {
|
||||
expect(keys).to.deep.equal(['Hello world', 'I', 'am', 'extracted', 'binary expression', 'conditional operator', 'FOO.bar']);
|
||||
});
|
||||
|
||||
it('should extract split strings', () => {
|
||||
const contents = `
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
_('Hello ' + 'world');
|
||||
_('This is 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 is a very very very very long line.',
|
||||
'Mix of different types'
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -0,0 +1,42 @@
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { PostProcessorInterface } from '../../src/post-processors/post-processor.interface';
|
||||
import { NullAsDefaultValuePostProcessor } from '../../src/post-processors/null-as-default-value.post-processor';
|
||||
import { TranslationCollection } from '../../src/utils/translation.collection';
|
||||
|
||||
describe('NullAsDefaultValuePostProcessor', () => {
|
||||
|
||||
let processor: PostProcessorInterface;
|
||||
|
||||
beforeEach(() => {
|
||||
processor = new NullAsDefaultValuePostProcessor();
|
||||
});
|
||||
|
||||
it('should use null as default value', () => {
|
||||
const draft = new TranslationCollection({ 'String A': '' });
|
||||
const extracted = new TranslationCollection({ 'String A': '' });
|
||||
const existing = new TranslationCollection();
|
||||
expect(processor.process(draft, extracted, existing).values).to.deep.equal({
|
||||
'String A': null
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep existing value even if it is an empty string', () => {
|
||||
const draft = new TranslationCollection({ 'String A': '' });
|
||||
const extracted = new TranslationCollection({ 'String A': '' });
|
||||
const existing = new TranslationCollection({ 'String A': '' });
|
||||
expect(processor.process(draft, extracted, existing).values).to.deep.equal({
|
||||
'String A': ''
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep existing value', () => {
|
||||
const draft = new TranslationCollection({ 'String A': 'Streng A' });
|
||||
const extracted = new TranslationCollection({ 'String A': 'Streng A' });
|
||||
const existing = new TranslationCollection({ 'String A': 'Streng A' });
|
||||
expect(processor.process(draft, extracted, existing).values).to.deep.equal({
|
||||
'String A': 'Streng A'
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -12,7 +12,10 @@
|
||||
],
|
||||
"module": "commonjs",
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true
|
||||
"sourceMap": true,
|
||||
"typeRoots" : [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
|
Reference in New Issue
Block a user