Repository: lingui/js-lingui
Pull request #737 (2020-09-14 17:31:34)

Add an ES module wrapper
 With this wrapper, a Node.js based ES module can use the *named import* syntax. E.g. `import {i18n} ...`

This PR belongs to this issue: #736 

vercel[bot]: This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).  
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: [https://vercel.com/lingui-js/js-lingui/lsti94f2m](https://vercel.com/lingui-js/js-lingui/lsti94f2m)  
✅ Preview: *In Progress*


codecov[bot]: # [Codecov](https://codecov.io/gh/lingui/js-lingui/pull/737?src=pr&el=h1) Report
> Merging [#737](https://codecov.io/gh/lingui/js-lingui/pull/737?src=pr&el=desc) into [next](https://codecov.io/gh/lingui/js-lingui/commit/8adf7c162129b8771074e8c677d32f94755c3dba?el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/lingui/js-lingui/pull/737/graphs/tree.svg?width=650&height=150&src=pr&token=CuJ1VD5BY5)](https://codecov.io/gh/lingui/js-lingui/pull/737?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##             next     #737   +/-   ##
=======================================
  Coverage   83.85%   83.85%           
=======================================
  Files          38       38           
  Lines        1214     1214           
  Branches      319      319           
=======================================
  Hits         1018     1018           
  Misses        120      120           
  Partials       76       76           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/lingui/js-lingui/pull/737?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lingui/js-lingui/pull/737?src=pr&el=footer). Last update [8adf7c1...0c63a0f](https://codecov.io/gh/lingui/js-lingui/pull/737?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/packages/cli/src/api/extractors/babel.ts b/packages/cli/src/api/extractors/babel.ts
index 4ede39c2..1aef493c 100644
--- a/packages/cli/src/api/extractors/babel.ts
+++ b/packages/cli/src/api/extractors/babel.ts
@@ -1,11 +1,14 @@
-import { transformFileSync } from "@babel/core"
+import { transformFileSync, DEFAULT_EXTENSIONS } from "@babel/core"
 
 import linguiExtractMessages from "@lingui/babel-plugin-extract-messages"
 
 import { BabelOptions, ExtractorType } from "./types"
 import { projectType } from "../detect"
 
-const babelRe = /\.jsx?$/i
+const babelRe = new RegExp(
+	"\\.(" + DEFAULT_EXTENSIONS.map(ext => ext.slice(1)).join("|") + ")$",
+	"i"
+)
 
 const extractor: ExtractorType = {
   match(filename) {
diff --git a/packages/cli/src/lingui-compile.ts b/packages/cli/src/lingui-compile.ts
index 6d8a66d3..85bff1b4 100644
--- a/packages/cli/src/lingui-compile.ts
+++ b/packages/cli/src/lingui-compile.ts
@@ -31,6 +31,9 @@ function command(config, options) {
 
   console.error("Compiling message catalogs…")
 
+  if(config.pseudoLocale) {
+    config.locales.push(config.pseudoLocale)
+  }
   config.locales.forEach((locale) => {
     const [language] = locale.split(/[_-]/)
     if (locale !== config.pseudoLocale && !plurals[language]) {
@@ -44,10 +47,13 @@ function command(config, options) {
     }
 
     catalogs.forEach((catalog) => {
-      const messages = catalog.getTranslations(locale, {
-        fallbackLocale: config.fallbackLocale,
-        sourceLocale: config.sourceLocale,
-      })
+      const messages = catalog.getTranslations(
+        locale === config.pseudoLocale ? config.sourceLocale: locale,
+        {
+          fallbackLocale: config.fallbackLocale,
+          sourceLocale: config.sourceLocale,
+        }
+      )
 
       if (!options.allowEmpty) {
         const missing = R.values(messages)
diff --git a/packages/core/npm/esm/index.js b/packages/core/npm/esm/index.js
new file mode 100644
index 00000000..7a8b32ee
--- /dev/null
+++ b/packages/core/npm/esm/index.js
@@ -0,0 +1,6 @@
+import i18nModule from '../index.js'
+
+export const setupI18n = i18nModule.setupI18n
+export const I18n = i18nModule.I18n
+export const i18n = i18nModule.i18n
+export const formats = i18nModule.formats
diff --git a/packages/core/npm/esm/package.json b/packages/core/npm/esm/package.json
new file mode 100644
index 00000000..3dbc1ca5
--- /dev/null
+++ b/packages/core/npm/esm/package.json
@@ -0,0 +1,3 @@
+{
+  "type": "module"
+}
diff --git a/packages/core/package.json b/packages/core/package.json
index 9aa33bf4..95a0b5d2 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -27,11 +27,16 @@
   "engines": {
     "node": ">=10.0.0"
   },
+  "exports": {
+    "require": "./index.js",
+    "import": "./esm/index.js"
+  },
   "files": [
     "LICENSE",
     "README.md",
     "index.js",
-    "cjs/"
+    "cjs/",
+    "esm/"
   ],
   "dependencies": {
     "@babel/runtime": "^7.11.2",


Test patch:
diff --git a/packages/cli/src/api/extract.test.ts b/packages/cli/src/api/extract.test.ts
index ab131cf4..6f5ed850 100644
--- a/packages/cli/src/api/extract.test.ts
+++ b/packages/cli/src/api/extract.test.ts
@@ -10,13 +10,18 @@ describe("extract", function () {
   let extract, babel, typescript
 
   beforeAll(() => {
+
+    // References to the real match functions
+    const babelMatch = require("./extractors/babel").default.match
+    const tsMatch = require("./extractors/typescript").default.match
+
     jest.doMock("./extractors/babel", () => ({
-      match: jest.fn((filename) => filename.endsWith(".js")),
+      match: jest.fn(babelMatch),
       extract: jest.fn(),
     }))
 
     jest.doMock("./extractors/typescript", () => ({
-      match: jest.fn((filename) => filename.endsWith(".ts")),
+      match: jest.fn(tsMatch),
       extract: jest.fn(),
     }))
 
@@ -31,6 +36,10 @@ describe("extract", function () {
 
         components: {
           "Babel.js": "",
+          "Babel.jsx": "",
+          "Babel.es6": "",
+          "Babel.es": "",
+          "Babel.mjs": "",
           "Typescript.ts": "",
           forbidden: {
             "apple.js": "",
@@ -60,33 +69,80 @@ describe("extract", function () {
     expect(babel.match).toHaveBeenCalledWith(
       path.join("src", "components", "Babel.js")
     )
-    expect(babel.match).toHaveBeenCalledWith(path.join("src", "index.html"))
+    expect(babel.match).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.jsx")
+    )
+    expect(babel.match).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.es6")
+    )
+    expect(babel.match).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.es")
+    )
+    expect(babel.match).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.mjs")
+    )
+		
+    expect(babel.match).toHaveBeenCalledWith(
+			path.join("src", "index.html")
+    )
 
     // This file is ignored
     expect(babel.extract).not.toHaveBeenCalledWith(
       path.join("src", "index.html")
     )
 
+    const extractArgs = [
+      "locale", 
+      { babelOptions: {}, ignore: ["forbidden"]}
+    ]
     expect(babel.extract).toHaveBeenCalledWith(
       path.join("src", "components", "Babel.js"),
-      "locale",
-      { babelOptions: {}, ignore: ["forbidden"] }
+      ...extractArgs
+    )
+    expect(babel.extract).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.jsx"),
+      ...extractArgs
+    )
+    expect(babel.extract).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.es6"),
+      ...extractArgs
+    )
+    expect(babel.extract).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.es"),
+      ...extractArgs
+    )
+    expect(babel.extract).toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.mjs"),
+      ...extractArgs
     )
     expect(babel.extract).not.toHaveBeenCalledWith(
       path.join("src", "components", "Typescript.ts"),
-      "locale",
-      { babelOptions: {}, ignore: ["forbidden"] }
+      ...extractArgs
     )
 
     expect(typescript.extract).not.toHaveBeenCalledWith(
       path.join("src", "components", "Babel.js"),
-      "locale",
-      { babelOptions: {}, ignore: ["forbidden"] }
+      ...extractArgs
+    )
+    expect(typescript.extract).not.toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.jsx"),
+      ...extractArgs
+    )
+    expect(typescript.extract).not.toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.es6"),
+      ...extractArgs
+    )
+    expect(typescript.extract).not.toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.es"),
+      ...extractArgs
+    )
+    expect(typescript.extract).not.toHaveBeenCalledWith(
+      path.join("src", "components", "Babel.mjs"),
+      ...extractArgs
     )
     expect(typescript.extract).toHaveBeenCalledWith(
       path.join("src", "components", "Typescript.ts"),
-      "locale",
-      { babelOptions: {}, ignore: ["forbidden"] }
+      ...extractArgs
     )
   })
 })