Repository: i18next/i18next-parser
Pull request #691 (2022-11-14 12:26:21)

feat: add support for `Translation` render prop
### Why am I submitting this PR

Currently the parser doesn't take into account `<Translation>` namespace for children expression within the render prop.

```
<Translation ns="foo">{(t) => t("some_key")}</Translation>

// js lexer result will miss namespace `foo`, assigning keys to the default one
{ key: "some_key" }
```

There's no documentation related to translation components so am not sure if there's any to add here as well. 

Added test watch script to ease contributions. Figured I'd add that as well since it can benefit others. How I used it:
```
yarn test:watch test/lexers/jsx-lexer.test.js
```

### Does it fix an existing ticket?

Yes #702

### Checklist

- [x] only relevant code is changed (make a diff before you submit the PR)
- [x] tests are included and pass: `yarn test` (see [details here](https://github.com/i18next/i18next-parser/blob/master/docs/development.md#tests))
- [x] documentation is changed or added



Patch:
diff --git a/package.json b/package.json
index 7c2e6b1..9fb410d 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
     "coverage": "c8 --all --include='src/**/*[.js|.jsx|.ts|.tsx]' --reporter=lcov --reporter=text yarn test",
     "test": "mocha -r @babel/register -r @babel/polyfill --recursive test/*.test.js test/**/*.test.js",
     "test:cli": "yarn -s build && ./bin/cli.js '**/*.html' -o 'test/manual/$LOCALE/$NAMESPACE.json' && ./bin/cli.js -c test/cli/i18next-parser.config.js && ./bin/cli.js -c test/cli/i18next-parser.config.mjs && ./bin/cli.js -c test/cli/i18next-parser.config.ts && ./bin/cli.js -c test/cli/i18next-parser.config.yaml",
+    "test:watch": "mocha -r @babel/register -r @babel/polyfill --watch --parallel --recursive",
     "watch": "babel src -d dist -w",
     "prettify": "prettier --write \"{src,test}/**/*.js\"",
     "build": "babel src -d dist",
diff --git a/src/lexers/jsx-lexer.js b/src/lexers/jsx-lexer.js
index 0546e8a..830ef0a 100644
--- a/src/lexers/jsx-lexer.js
+++ b/src/lexers/jsx-lexer.js
@@ -153,6 +153,11 @@ export default class JsxLexer extends JavascriptLexer {
       const entry = {}
       entry.key = getKey(tagNode)
       return entry.key ? entry : null
+    } else if (tagNode.tagName.text === 'Translation') {
+      const namespace = getPropValue(tagNode, 'ns')
+      if (namespace) {
+        this.defaultNamespace = namespace
+      }
     }
   }
 


Test patch:
diff --git a/test/lexers/jsx-lexer.test.js b/test/lexers/jsx-lexer.test.js
index b3f4ded..b5de066 100644
--- a/test/lexers/jsx-lexer.test.js
+++ b/test/lexers/jsx-lexer.test.js
@@ -11,6 +11,27 @@ describe('JsxLexer', () => {
     })
   })
 
+  describe('<Translation>', () => {
+    it('extracts keys from render prop', (done) => {
+      const Lexer = new JsxLexer()
+      const content = `<Translation>{(t) => <>{t("first", "Main")}{t("second")}</>}</Translation>`
+      assert.deepEqual(Lexer.extract(content), [
+        { defaultValue: 'Main', key: 'first' },
+        { key: 'second' },
+      ])
+      done()
+    })
+
+    it('sets ns (namespace) for expressions within render prop', (done) => {
+      const Lexer = new JsxLexer()
+      const content = `<Translation ns="foo">{(t) => t("first")}</Translation>`
+      assert.deepEqual(Lexer.extract(content), [
+        { key: 'first', namespace: 'foo' },
+      ])
+      done()
+    })
+  })
+
   describe('<Trans>', () => {
     it('extracts keys from i18nKey attributes from closing tags', (done) => {
       const Lexer = new JsxLexer()