Repository: vendure-ecommerce/ngx-translate-extract
Pull request #49 (2024-05-13 11:42:12)

feat!: Add check if key is pre-existing
Added a copy of the `--key-as-default-value` flag to keep empty translations empty when the `--key-as-initial-default-value` flag is in use. This prevents intentionally emptied translations to not be filled again with the key when it already exists

See https://github.com/vendure-ecommerce/ngx-translate-extract/issues/48


Patch:
diff --git a/README.md b/README.md
index 2ec7dde..ebcfbfb 100644
--- a/README.md
+++ b/README.md
@@ -115,9 +115,10 @@ Output
   --strip-prefix, -sp         Strip prefix from key                                                       [string]
 
 Extracted key value (defaults to empty string)
-  --key-as-default-value, -k     Use key as default value                                                [boolean]
-  --null-as-default-value, -n    Use null as default value                                               [boolean]
-  --string-as-default-value, -d  Use string as default value                                              [string]
+  --key-as-default-value, -k           Use key as default value                                          [boolean]
+  --key-as-initial-default-value, -ki  Use key as initial default value                                  [boolean]
+  --null-as-default-value, -n          Use null as default value                                         [boolean]
+  --string-as-default-value, -d        Use string as default value                                        [string]
 
 Options:
   --version, -v  Show version number                                                                     [boolean]
diff --git a/src/cli/cli.ts b/src/cli/cli.ts
index ded7af5..d486c38 100755
--- a/src/cli/cli.ts
+++ b/src/cli/cli.ts
@@ -11,6 +11,7 @@ import { FunctionParser } from '../parsers/function.parser.js';
 import { PostProcessorInterface } from '../post-processors/post-processor.interface.js';
 import { SortByKeyPostProcessor } from '../post-processors/sort-by-key.post-processor.js';
 import { KeyAsDefaultValuePostProcessor } from '../post-processors/key-as-default-value.post-processor.js';
+import { KeyAsInitialDefaultValuePostProcessor } from '../post-processors/key-as-initial-default-value.post-processor.js';
 import { NullAsDefaultValuePostProcessor } from '../post-processors/null-as-default-value.post-processor.js';
 import { StringAsDefaultValuePostProcessor } from '../post-processors/string-as-default-value.post-processor.js';
 import { PurgeObsoleteKeysPostProcessor } from '../post-processors/purge-obsolete-keys.post-processor.js';
@@ -99,19 +100,25 @@ const cli = await y
 		alias: 'k',
 		describe: 'Use key as default value',
 		type: 'boolean',
-		conflicts: ['null-as-default-value', 'string-as-default-value']
+		conflicts: ['key-as-initial-default-value', 'null-as-default-value', 'string-as-default-value']
+	})
+	.option('key-as-initial-default-value', {
+		alias: 'ki',
+		describe: 'Use key as initial default value',
+		type: 'boolean',
+		conflicts: ['key-as-default-value', 'null-as-default-value', 'string-as-default-value']
 	})
 	.option('null-as-default-value', {
 		alias: 'n',
 		describe: 'Use null as default value',
 		type: 'boolean',
-		conflicts: ['key-as-default-value', 'string-as-default-value']
+		conflicts: ['key-as-default-value', 'key-as-initial-default-value', 'string-as-default-value']
 	})
 	.option('string-as-default-value', {
 		alias: 'd',
 		describe: 'Use string as default value',
 		type: 'string',
-		conflicts: ['null-as-default-value', 'key-as-default-value']
+		conflicts: ['null-as-default-value', 'key-as-default-value', 'key-as-initial-default-value']
 	})
 	.option('strip-prefix', {
 		alias: 'sp',
@@ -119,8 +126,9 @@ const cli = await y
 		type: 'string'
 	})
 	.group(['format', 'format-indentation', 'sort', 'clean', 'replace', 'strip-prefix'], 'Output')
-	.group(['key-as-default-value', 'null-as-default-value', 'string-as-default-value'], 'Extracted key value (defaults to empty string)')
+	.group(['key-as-default-value', 'key-as-initial-default-value', 'null-as-default-value', 'string-as-default-value'], 'Extracted key value (defaults to empty string)')
 	.conflicts('key-as-default-value', 'null-as-default-value')
+	.conflicts('key-as-initial-default-value', 'null-as-default-value')
 	.example('$0 -i ./src-a/ -i ./src-b/ -o strings.json', 'Extract (ts, html) from multiple paths')
 	.example("$0 -i './{src-a,src-b}/' -o strings.json", 'Extract (ts, html) from multiple paths using brace expansion')
 	.example('$0 -i ./src/ -o ./i18n/da.json -o ./i18n/en.json', 'Extract (ts, html) and save to da.json and en.json')
@@ -156,6 +164,8 @@ if (cli.clean) {
 }
 if (cli.keyAsDefaultValue) {
 	postProcessors.push(new KeyAsDefaultValuePostProcessor());
+} else if (cli.keyAsInitialDefaultValue) {
+	postProcessors.push(new KeyAsInitialDefaultValuePostProcessor());
 } else if (cli.nullAsDefaultValue) {
 	postProcessors.push(new NullAsDefaultValuePostProcessor());
 } else if (cli.stringAsDefaultValue) {
diff --git a/src/index.ts b/src/index.ts
index 58a0720..1e8ebd4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,6 +19,7 @@ export * from './compilers/po.compiler.js';
 
 export * from './post-processors/post-processor.interface.js';
 export * from './post-processors/key-as-default-value.post-processor.js';
+export * from './post-processors/key-as-initial-default-value.post-processor.js';
 export * from './post-processors/purge-obsolete-keys.post-processor.js';
 export * from './post-processors/sort-by-key.post-processor.js';
 export * from './post-processors/strip-prefix.post-processor.js';
diff --git a/src/post-processors/key-as-initial-default-value.post-processor.ts b/src/post-processors/key-as-initial-default-value.post-processor.ts
new file mode 100644
index 0000000..ccb31e5
--- /dev/null
+++ b/src/post-processors/key-as-initial-default-value.post-processor.ts
@@ -0,0 +1,10 @@
+import {TranslationCollection, TranslationInterface} from '../utils/translation.collection.js';
+import { PostProcessorInterface } from './post-processor.interface.js';
+
+export class KeyAsInitialDefaultValuePostProcessor implements PostProcessorInterface {
+	public name: string = 'KeyAsInitialDefaultValue';
+
+	public process(draft: TranslationCollection, extracted: TranslationCollection, existing: TranslationCollection): TranslationCollection {
+		return draft.map((key: string, val: TranslationInterface): TranslationInterface => val.value === '' && !existing.has(key) ? {value: key, sourceFiles: (val?.sourceFiles || [])} : val);
+	}
+}


Test patch:
diff --git a/tests/post-processors/key-as-initial-default-value.post-processor.spec.ts b/tests/post-processors/key-as-initial-default-value.post-processor.spec.ts
new file mode 100644
index 0000000..cd776db
--- /dev/null
+++ b/tests/post-processors/key-as-initial-default-value.post-processor.spec.ts
@@ -0,0 +1,33 @@
+import { describe, beforeEach, expect, it } from 'vitest';
+
+import { PostProcessorInterface } from '../../src/post-processors/post-processor.interface.js';
+import { KeyAsInitialDefaultValuePostProcessor } from '../../src/post-processors/key-as-initial-default-value.post-processor.js';
+import { TranslationCollection } from '../../src/utils/translation.collection.js';
+
+describe('KeyAsInitialDefaultValuePostProcessor', () => {
+	let processor: PostProcessorInterface;
+
+	beforeEach(() => {
+		processor = new KeyAsInitialDefaultValuePostProcessor();
+	});
+
+	it('should use key as default value', () => {
+		const collection = new TranslationCollection({
+			'I have no value': { value: '', sourceFiles: [] },
+			'I have no value but I exist': { value: '', sourceFiles: [] },
+			'I am already translated': { value: 'Jeg er allerede oversat', sourceFiles: [] },
+			'Use this key as value as well': { value: '', sourceFiles: ['path/to/file.ts'] }
+		});
+		const extracted = new TranslationCollection();
+		const existing = new TranslationCollection({
+			'I have no value but I exist': { value: '', sourceFiles: [] }
+		});
+
+		expect(processor.process(collection, extracted, existing).values).to.deep.equal({
+			'I have no value': { value: 'I have no value', sourceFiles: [] },
+			'I have no value but I exist': { value: '', sourceFiles: [] },
+			'I am already translated': { value: 'Jeg er allerede oversat', sourceFiles: [] },
+			'Use this key as value as well': { value: 'Use this key as value as well', sourceFiles: ['path/to/file.ts'] }
+		});
+	});
+});