Repository: i18next/i18next-parser
Pull request #418 (2021-09-15 07:53:06)

Sort option as a function
### Why am I submitting this PR

Needed a custom sort function to synchronise with a translation service.

### Does it fix an existing ticket?

No

### 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


karellm: @simonasdev Thanks for the PR. Please note that the sort logic is broken as you can see in #400 and #169 . Would you be interested in tackling this too?

On a side note, can you please remove the style changes to the README?
simonasdev: Removed prettier changes to README. But I wouldn't call the current sort broken, it's just how `localeCompare` works - albeit unexpectedly, but consistently. In my case I just needed a simple ASCII sort, as in the test example I've made.

Unless you would consider making ASCII sort the default?

Patch:
diff --git a/README.md b/README.md
index 0d9016e..3041ee7 100644
--- a/README.md
+++ b/README.md
@@ -179,7 +179,7 @@ module.exports = {
   // relative to the location of the configuration file
 
   sort: false,
-  // Whether or not to sort the catalog
+  // Whether or not to sort the catalog. Can also be a [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters)
 
   skipDefaultValues: false,
   // Whether to ignore default values
diff --git a/dist/transform.js b/dist/transform.js
index 823b976..0c19c5f 100644
--- a/dist/transform.js
+++ b/dist/transform.js
@@ -126,8 +126,11 @@ i18nTransform = /*#__PURE__*/function (_Transform) {(0, _inherits2["default"])(i
     } }, { key: "_flush", value:
 
     function _flush(done) {var _this2 = this;
-      if (this.options.sort) {
-        this.entries = this.entries.sort(function (a, b) {return a.key.localeCompare(b.key);});
+      var sort = this.options.sort;
+      if (sort) {
+        this.entries = this.entries.sort(
+        typeof sort === 'function' ? sort : function (a, b) {return a.key.localeCompare(b.key);});
+
       }var _iterator2 = _createForOfIteratorHelper(
 
       this.options.locales),_step2;try {var _loop = function _loop() {var locale = _step2.value;
diff --git a/src/transform.js b/src/transform.js
index 6910302..cc7ef2b 100644
--- a/src/transform.js
+++ b/src/transform.js
@@ -126,8 +126,11 @@ export default class i18nTransform extends Transform {
   }
 
   _flush(done) {
-    if (this.options.sort) {
-      this.entries = this.entries.sort((a, b) => a.key.localeCompare(b.key))
+    const { sort } = this.options
+    if (sort) {
+      this.entries = this.entries.sort(
+        typeof sort === 'function' ? sort : (a, b) => a.key.localeCompare(b.key)
+      )
     }
 
     for (const locale of this.options.locales) {


Test patch:
diff --git a/test/parser.test.js b/test/parser.test.js
index 172cb56..2b2a66e 100644
--- a/test/parser.test.js
+++ b/test/parser.test.js
@@ -1660,14 +1660,14 @@ describe('parser', () => {
         i18nextParser.end(fakeFile)
       })
 
-      it('supports sort as an option', (done) => {
+      it('supports sort as a boolean', (done) => {
         let result
         const i18nextParser = new i18nTransform({
           sort: true,
         })
         const fakeFile = new Vinyl({
           contents: Buffer.from(
-            "t('ccc'); t('aaa'); t('bbb.bbb'); t('bbb.aaa')"
+            "t('aaA'); t('aaa'); t('bbb.bbb'); t('bbb.aaa')"
           ),
           path: 'file.js',
         })
@@ -1678,13 +1678,39 @@ describe('parser', () => {
           }
         })
         i18nextParser.once('end', () => {
-          assert.sameOrderedMembers(Object.keys(result), ['aaa', 'bbb', 'ccc'])
+          assert.sameOrderedMembers(Object.keys(result), ['aaa', 'aaA', 'bbb'])
           assert.sameOrderedMembers(Object.keys(result.bbb), ['aaa', 'bbb'])
           done()
         })
 
         i18nextParser.end(fakeFile)
       })
+
+      it('supports sort as a function', (done) => {
+        let result
+        const i18nextParser = new i18nTransform({
+          sort: (a, b) => (a.key > b.key) - (a.key < b.key),
+        })
+        const fakeFile = new Vinyl({
+          contents: Buffer.from(
+            "t('aaa'); t('aaA'); t('bbb.bbb'); t('bbb.bbB')"
+          ),
+          path: 'file.js',
+        })
+
+        i18nextParser.on('data', (file) => {
+          if (file.relative.endsWith(enLibraryPath)) {
+            result = JSON.parse(file.contents)
+          }
+        })
+        i18nextParser.once('end', () => {
+          assert.sameOrderedMembers(Object.keys(result), ['aaA', 'aaa', 'bbb'])
+          assert.sameOrderedMembers(Object.keys(result.bbb), ['bbB', 'bbb'])
+          done()
+        })
+
+        i18nextParser.end(fakeFile)
+      })
     })
   })