Repository: gilbsgilbs/babel-plugin-i18next-extract (ts)

Issue:
Support config for don't use cache
Here is my config 
```
{
        keyAsDefaultValue: true,
        keyAsDefaultValueForDerivedKeys: false,
}
```

The problem is when I edit the translation file, after that, I add a new key in component, It will write to the translation file the old content with new key, the content I have edited is lost in the wild. So, I need a config for disable cache in this line https://github.com/gilbsgilbs/babel-plugin-i18next-extract/blob/55894cab44bbb3d199167b70c1525bc28621093c/src/exporters/index.ts#L122

Thank you 🙏 

Pull request description:
fix(exporter): fix cache overwriting changes to translation files
fixes #78

Add caching abilities to check if :
- translation file as change and must be updated in cache (based on last modified time)
- if the old version does not equal the actual we update the translation file (base on `originalTranslationFile` & `translationFile variable`)

## Context

Environment: `development`
Tool:
* Webpack (with watch option)
* babel-loader
* babel-plugin-i18next-extract

## Expected

Our problem is the plugin re-write the translation file using the version it had at build time.

Example:

locale.json
```json
{
  "foo": ""
}
```
build ->  the plugin has the key 'foo' and the value ''

Inside locale.json I change the value of `foo` with `easy` and I save the file.

locale.json
```json
{
  "foo": "easy"
}
```
I add a key in my view named 'toto', the plugin extract that new key and add it inside our translation file.

theoretically locale.json should look like this
```json
{
  "foo": "easy",
  "toto": ""
}
```

but the plugin keeps the old version (version at the build time) and I got this:
```json
{
   "foo": "",
   "toto": ""
}
```

### Fixes

I have added : 
  * a check on the `mtime` of the file being processed 
  * a check to prevent from writing the translation file if it equals the old version

* [x] I have added unit test for those cases
* [ ] documentation (if needed)

Patch:
diff --git a/package.json b/package.json
index 0f3bf31..4f0f8ca 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
   "dependencies": {
     "@babel/core": "^7.11.6",
     "@babel/types": "7.9.6",
+    "deepmerge": "^4.2.2",
     "i18next": "^19.7.0",
     "json-stable-stringify": "^1.0.1"
   },
diff --git a/src/exporters/index.ts b/src/exporters/index.ts
index 3c5d38b..8b82562 100644
--- a/src/exporters/index.ts
+++ b/src/exporters/index.ts
@@ -1,6 +1,8 @@
 import fs from 'fs';
 import path from 'path';
 
+import deepmerge from 'deepmerge';
+
 import { Config } from '../config';
 import { TranslationKey } from '../keys';
 
@@ -127,15 +129,14 @@ export default function exportTranslationKeys(
   }
 
   for (const [filePath, keysForFilepath] of Object.entries(keysPerFilepath)) {
-    if (!(filePath in cache.originalTranslationFiles)) {
-      // Cache original translation file so that we don't loose it across babel
-      // passes.
-      cache.originalTranslationFiles[filePath] = loadTranslationFile(
-        exporter,
-        config,
-        filePath,
-      );
-    }
+    cache.originalTranslationFiles[filePath] = deepmerge(
+      cache.originalTranslationFiles[filePath] ?? {},
+      loadTranslationFile(exporter, config, filePath),
+      {
+        // Overwrites the existing array values completely rather than concatenating them
+        arrayMerge: (dest, source) => source,
+      },
+    );
 
     const originalTranslationFile = cache.originalTranslationFiles[filePath];
     let translationFile =
@@ -166,6 +167,7 @@ export default function exportTranslationKeys(
 
     // Finally do the export
     const directoryPath = path.dirname(filePath);
+
     fs.mkdirSync(directoryPath, { recursive: true });
     fs.writeFileSync(
       filePath,


Test patch:
diff --git a/tests/exporters/exporter.test.ts b/tests/exporters/exporter.test.ts
index ea1b6d2..3a5d152 100644
--- a/tests/exporters/exporter.test.ts
+++ b/tests/exporters/exporter.test.ts
@@ -88,4 +88,39 @@ describe('Test exporter works', () => {
       newKey2: '',
     });
   });
+
+  it('reload translation file and merge with actual cache', () => {
+    const outputPath = path.join(outputDir, 'if_locale_file_changes.json');
+    fs.writeJSONSync(outputPath, { presentAtInit: 'foo' });
+
+    const config = parseConfig({ outputPath });
+    const cache = createExporterCache();
+
+    // view key
+    const key0 = createTranslationKey('presentAtInit');
+
+    // extract at init
+    exportTranslationKeys([key0], 'fr', config, cache);
+
+    expect(fs.readJSONSync(outputPath)).toEqual({
+      presentAtInit: 'foo',
+    });
+
+    // update the locale file directly
+    fs.writeJSONSync(outputPath, {
+      presentAtInit: 'foo updated directly in file after init',
+    });
+
+    // view key
+    const key1 = createTranslationKey('newKeyAfterInit');
+
+    // extract second time
+    exportTranslationKeys([key0, key1], 'fr', config, cache);
+
+    // the locale file should have disk changes + new view key (newKeyAfterInit)
+    expect(fs.readJSONSync(outputPath)).toEqual({
+      presentAtInit: 'foo updated directly in file after init',
+      newKeyAfterInit: '',
+    });
+  });
 });