Repository: i18next/i18next-parser (js)

Issue:
Conditional `useKeysAsDefaultValue`
## 🚀 Feature Proposal

I would like to enable `useKeysAsDefaultValue` conditionally based on the generated locale.

## Motivation

I use natural keys, so for the source language (English, in my case), I would like to generate files where the key is set to the default value. However, for all other languages, I would like to generate empty values so it's clear which parts still have to be translated.

## Example

```js
skipDefaultValues: true,
useKeysAsDefaultValue: (locale) => locale === defaultLocale ? true : false
```

---

I'd be happy to send a PR for this if it's something you are willing to add :)

Pull request:
Accept a function for the defaultValue, useKeysAsDefaultValue, and skipDefaultValues configuration options
This is https://github.com/i18next/i18next-parser/pull/224, rebased on master. I removed some small logic flow changes to keep the code closer to master.

### Does it fix an existing ticket?

Closes #299 

### Checklist

- [X] only relevant code is changed (make a diff before you submit the PR)
- [X] tests are included and pass (see [details here](https://github.com/i18next/i18next-parser/blob/master/docs/development.md#tests))
- [X] documentation is changed or added
- [X] I ran `yarn build` to compile and prettify the code

Patch:
diff --git a/.gitignore b/.gitignore
index f01319f..761e45c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ Thumbs.db
 *.swp
 /sftp-config.json
 /.vscode
+.history
 
 # node files
 node_modules/
diff --git a/README.md b/README.md
index 75dad2a..cde484a 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,7 @@ module.exports = {
 
   defaultValue: '',
   // Default value to give to empty keys
+  // You may also specify a function accepting the locale, namespace, and key as arguments
 
   indentation: 2,
   // Indentation of the catalog files
@@ -177,11 +178,13 @@ module.exports = {
   // Whether or not to sort the catalog
 
   skipDefaultValues: false,
-  // Whether to ignore default values.
+  // Whether to ignore default values
+  // You may also specify a function accepting the locale and namespace as arguments
 
   useKeysAsDefaultValue: false,
   // Whether to use the keys as the default value; ex. "Hello": "Hello", "World": "World"
   // This option takes precedence over the `defaultValue` and `skipDefaultValues` options
+  // You may also specify a function accepting the locale and namespace as arguments
 
   verbose: false,
   // Display info about the parsing including some stats
diff --git a/dist/helpers.js b/dist/helpers.js
index 7152d30..a288b29 100644
--- a/dist/helpers.js
+++ b/dist/helpers.js
@@ -18,21 +18,39 @@ function dotPathToHash(entry) {var target = arguments.length > 1 && arguments[1]
   }
 
   var separator = options.separator || '.';
+
+  var key = entry.keyWithNamespace.substring(
+  entry.keyWithNamespace.indexOf(separator) + separator.length,
+  entry.keyWithNamespace.length);
+
+
+  var defaultValue =
+  typeof options.value === 'function' ?
+  options.value(options.locale, entry.namespace, key) :
+  options.value;
+
+  var skipDefaultValues =
+  typeof options.skipDefaultValues === 'function' ?
+  options.skipDefaultValues(options.locale, entry.namespace) :
+  options.skipDefaultValues;
+
+  var useKeysAsDefaultValue =
+  typeof options.useKeysAsDefaultValue === 'function' ?
+  options.useKeysAsDefaultValue(options.locale, entry.namespace) :
+  options.useKeysAsDefaultValue;
+
   var newValue =
   entry["defaultValue_".concat(options.suffix)] ||
   entry.defaultValue ||
-  options.value ||
+  defaultValue ||
   '';
 
-  if (options.skipDefaultValues) {
+  if (skipDefaultValues) {
     newValue = '';
   }
 
-  if (options.useKeysAsDefaultValue) {
-    newValue = entry.keyWithNamespace.substring(
-    entry.keyWithNamespace.indexOf(separator) + separator.length,
-    entry.keyWithNamespace.length);
-
+  if (useKeysAsDefaultValue) {
+    newValue = key;
   }
 
   if (path.endsWith(separator)) {
diff --git a/dist/transform.js b/dist/transform.js
index 43f7317..05e4fee 100644
--- a/dist/transform.js
+++ b/dist/transform.js
@@ -140,6 +140,7 @@ i18nTransform = /*#__PURE__*/function (_Transform) {_inherits(i18nTransform, _Tr
           var transformEntry = function transformEntry(entry, suffix) {
             var _dotPathToHash = (0, _helpers.dotPathToHash)(entry, catalog, {
               suffix: suffix,
+              locale: locale,
               separator: _this2.options.keySeparator,
               value: _this2.options.defaultValue,
               useKeysAsDefaultValue: _this2.options.useKeysAsDefaultValue,
diff --git a/src/helpers.js b/src/helpers.js
index 5a04803..c1aa922 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -18,21 +18,39 @@ function dotPathToHash(entry, target = {}, options = {}) {
   }
 
   const separator = options.separator || '.'
+
+  const key = entry.keyWithNamespace.substring(
+    entry.keyWithNamespace.indexOf(separator) + separator.length,
+    entry.keyWithNamespace.length
+  )
+
+  const defaultValue =
+    typeof options.value === 'function'
+      ? options.value(options.locale, entry.namespace, key)
+      : options.value
+
+  const skipDefaultValues =
+    typeof options.skipDefaultValues === 'function'
+      ? options.skipDefaultValues(options.locale, entry.namespace)
+      : options.skipDefaultValues
+
+  const useKeysAsDefaultValue =
+    typeof options.useKeysAsDefaultValue === 'function'
+      ? options.useKeysAsDefaultValue(options.locale, entry.namespace)
+      : options.useKeysAsDefaultValue
+
   let newValue =
     entry[`defaultValue_${options.suffix}`] ||
     entry.defaultValue ||
-    options.value ||
+    defaultValue ||
     ''
 
-  if (options.skipDefaultValues) {
+  if (skipDefaultValues) {
     newValue = ''
   }
 
-  if (options.useKeysAsDefaultValue) {
-    newValue = entry.keyWithNamespace.substring(
-      entry.keyWithNamespace.indexOf(separator) + separator.length,
-      entry.keyWithNamespace.length
-    )
+  if (useKeysAsDefaultValue) {
+    newValue = key
   }
 
   if (path.endsWith(separator)) {
diff --git a/src/transform.js b/src/transform.js
index e67531a..926f43e 100644
--- a/src/transform.js
+++ b/src/transform.js
@@ -140,6 +140,7 @@ export default class i18nTransform extends Transform {
       const transformEntry = (entry, suffix) => {
         const { duplicate, conflict } = dotPathToHash(entry, catalog, {
           suffix,
+          locale,
           separator: this.options.keySeparator,
           value: this.options.defaultValue,
           useKeysAsDefaultValue: this.options.useKeysAsDefaultValue,


Test patch:
diff --git a/test/parser.test.js b/test/parser.test.js
index d2470ee..874ef3c 100644
--- a/test/parser.test.js
+++ b/test/parser.test.js
@@ -721,6 +721,86 @@ describe('parser', () => {
       i18nextParser.end(fakeFile)
     })
 
+    it('supports a defaultValue function', (done) => {
+      let result
+      const i18nextParser = new i18nTransform({
+        defaultValue: (locale, namespace, key) =>
+          `${locale}:${namespace}:${key}`,
+      })
+      const fakeFile = new Vinyl({
+        contents: Buffer.from("t('first')"),
+        path: 'file.js',
+      })
+
+      i18nextParser.on('data', (file) => {
+        if (file.relative.endsWith(enLibraryPath)) {
+          result = JSON.parse(file.contents)
+        }
+      })
+      i18nextParser.once('end', () => {
+        assert.deepEqual(result, { first: 'en:translation:first' })
+        done()
+      })
+
+      i18nextParser.end(fakeFile)
+    })
+
+    it('supports a useKeysAsDefaultValue function', (done) => {
+      let enResult
+      let arResult
+      const i18nextParser = new i18nTransform({
+        locales: ['en', 'ar'],
+        useKeysAsDefaultValue: (locale, namespace) => locale === 'en',
+      })
+      const fakeFile = new Vinyl({
+        contents: Buffer.from("t('first')"),
+        path: 'file.js',
+      })
+
+      i18nextParser.on('data', (file) => {
+        if (file.relative.endsWith(enLibraryPath)) {
+          enResult = JSON.parse(file.contents)
+        } else if (file.relative.endsWith(arLibraryPath)) {
+          arResult = JSON.parse(file.contents)
+        }
+      })
+      i18nextParser.once('end', () => {
+        assert.deepEqual(enResult, { first: 'first' })
+        assert.deepEqual(arResult, { first: '' })
+        done()
+      })
+
+      i18nextParser.end(fakeFile)
+    })
+
+    it('supports a skipDefaultValues function', (done) => {
+      let enResult
+      let arResult
+      const i18nextParser = new i18nTransform({
+        locales: ['en', 'ar'],
+        skipDefaultValues: (locale, namespace) => locale === 'en',
+      })
+      const fakeFile = new Vinyl({
+        contents: Buffer.from("t('first', { defaultValue: 'default' })"),
+        path: 'file.js',
+      })
+
+      i18nextParser.on('data', (file) => {
+        if (file.relative.endsWith(enLibraryPath)) {
+          enResult = JSON.parse(file.contents)
+        } else if (file.relative.endsWith(arLibraryPath)) {
+          arResult = JSON.parse(file.contents)
+        }
+      })
+      i18nextParser.once('end', () => {
+        assert.deepEqual(enResult, { first: '' })
+        assert.deepEqual(arResult, { first: 'default' })
+        done()
+      })
+
+      i18nextParser.end(fakeFile)
+    })
+
     it('supports a lineEnding', (done) => {
       let result
       const i18nextParser = new i18nTransform({