diff --git a/packages/cli/package.json b/packages/cli/package.json
index f9e1869f9..6f1f46620 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -45,12 +45,11 @@
"build/"
],
"dependencies": {
- "@babel/core": "^7.20.12",
- "@babel/generator": "^7.20.14",
- "@babel/parser": "^7.20.15",
- "@babel/plugin-syntax-jsx": "^7.18.6",
- "@babel/runtime": "^7.20.13",
- "@babel/types": "^7.20.7",
+ "@babel/core": "^7.21.0",
+ "@babel/generator": "^7.21.1",
+ "@babel/parser": "^7.21.2",
+ "@babel/runtime": "^7.21.0",
+ "@babel/types": "^7.21.2",
"@lingui/babel-plugin-extract-messages": "4.0.0-next.1",
"@lingui/conf": "4.0.0-next.1",
"@lingui/core": "4.0.0-next.1",
diff --git a/packages/cli/src/api/catalog.test.ts b/packages/cli/src/api/catalog.test.ts
index 76c8aad25..7a38ca493 100644
--- a/packages/cli/src/api/catalog.test.ts
+++ b/packages/cli/src/api/catalog.test.ts
@@ -16,6 +16,7 @@ import {
makeCatalog,
} from "../tests"
import { AllCatalogsType } from "./types"
+import { extractFromFiles } from "./catalog/extractFromFiles"
export const fixture = (...dirs: string[]) =>
path.resolve(__dirname, path.join("fixtures", ...dirs)) +
@@ -165,26 +166,47 @@ describe("Catalog", () => {
describe("collect", () => {
it("should support JSX and Typescript", async () => {
- const catalog = new Catalog(
- {
- name: "messages",
- path: "locales/{locale}",
- include: [fixture("collect-typescript-jsx/")],
- exclude: [],
- },
+ const messages = await extractFromFiles(
+ [
+ fixture("collect-typescript-jsx/jsx-syntax.jsx"),
+ fixture("collect-typescript-jsx/tsx-syntax.tsx"),
+ fixture("collect-typescript-jsx/macro.tsx"),
+ ],
mockConfig()
)
- const messages = await catalog.collect()
- expect(messages).toBeTruthy()
expect(messages).toMatchSnapshot()
})
- it("should support Flow syntax if enabled", async () => {
- process.env.LINGUI_CONFIG = path.join(
- __dirname,
- "fixtures/collect-syntax-flow/lingui.config.js"
+ it("should support experimental typescript decorators under a flag", async () => {
+ const messages = await extractFromFiles(
+ [fixture("collect-typescript-jsx/tsx-experimental-decorators.tsx")],
+ mockConfig({
+ extractorParserOptions: {
+ tsExperimentalDecorators: true,
+ },
+ })
)
+
+ expect(messages).toBeTruthy()
+ expect(messages).toMatchInlineSnapshot(`
+ {
+ xDAtGP: {
+ context: undefined,
+ extractedComments: [],
+ message: Message,
+ origin: [
+ [
+ collect-typescript-jsx/tsx-experimental-decorators.tsx,
+ 15,
+ ],
+ ],
+ },
+ }
+ `)
+ })
+
+ it("should support Flow syntax if enabled", async () => {
const catalog = new Catalog(
{
name: "messages",
@@ -200,7 +222,6 @@ describe("Catalog", () => {
)
const messages = await catalog.collect()
- expect(messages).toBeTruthy()
expect(messages).toMatchSnapshot()
})
it("should extract messages from source files", async () => {
diff --git a/packages/cli/src/api/extractors/babel.ts b/packages/cli/src/api/extractors/babel.ts
index 627166cb8..6bfe86bb4 100644
--- a/packages/cli/src/api/extractors/babel.ts
+++ b/packages/cli/src/api/extractors/babel.ts
@@ -30,22 +30,24 @@ const extractor: ExtractorType = {
async extract(filename, code, onMessageExtracted, ctx) {
const parserOptions = ctx.linguiConfig.extractorParserOptions
- const parserPlugins: ParserPlugin[] = [
- // https://babeljs.io/docs/en/babel-parser#latest-ecmascript-features
- [
- "decorators",
- {
- decoratorsBeforeExport: parserOptions?.decoratorsBeforeExport || true,
- },
- ],
- ]
+ // https://babeljs.io/docs/en/babel-parser#latest-ecmascript-features
+ const parserPlugins: ParserPlugin[] = []
if (
[/\.ts$/, /\.mts$/, /\.cts$/, /\.tsx$/].some((r) => filename.match(r))
) {
parserPlugins.push("typescript")
- } else if (parserOptions?.flow) {
- parserPlugins.push("flow")
+ if (parserOptions.tsExperimentalDecorators) {
+ parserPlugins.push("decorators-legacy")
+ } else {
+ parserPlugins.push("decorators")
+ }
+ } else {
+ parserPlugins.push("decorators")
+
+ if (parserOptions?.flow) {
+ parserPlugins.push("flow")
+ }
}
if ([/\.jsx$/, /\.tsx$/].some((r) => filename.match(r))) {
diff --git a/packages/cli/src/api/fixtures/collect-syntax-flow/lingui.config.js b/packages/cli/src/api/fixtures/collect-syntax-flow/lingui.config.js
deleted file mode 100644
index 265afcf7f..000000000
--- a/packages/cli/src/api/fixtures/collect-syntax-flow/lingui.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- *
- * @type {import('@lingui/conf').LinguiConfig}
- */
-module.exports = {
- locales: ["en", "cs"],
- extractorParserOptions: {
- flow: true
- }
-}
diff --git a/packages/cli/src/api/fixtures/collect-typescript-jsx/jsx-syntax.jsx b/packages/cli/src/api/fixtures/collect-typescript-jsx/jsx-syntax.jsx
index a169d7425..fe2bbffc0 100644
--- a/packages/cli/src/api/fixtures/collect-typescript-jsx/jsx-syntax.jsx
+++ b/packages/cli/src/api/fixtures/collect-typescript-jsx/jsx-syntax.jsx
@@ -5,34 +5,38 @@ const jsx =
Hello!
@Decorator()
export class TestDecorator {
@Decorator()
- prop;
+ prop
@Decorator()
- method() {};
+ method() {}
}
+export
+@Decorator()
+class TestDecoratorAfterExport {}
+
class A {
// classProperties
- b = 1;
+ b = 1
// classPrivateProperties
- #b = 1;
+ #b = 1
}
// dynamicImport
-import('./guy').then(a)
+import("./guy").then(a)
// exportNamespaceFrom
export * as ns from "mod"
// nullishCoalescingOperator
-const a = a ?? b;
+const a = a ?? b
// objectRestSpread
-const b = { b, ...c };
+const b = { b, ...c }
// optionalChaining
-const c = a?.b;
+const c = a?.b
// topLevelAwait
-await promise;
+await promise
diff --git a/packages/cli/src/api/fixtures/collect-typescript-jsx/lingui.config.js b/packages/cli/src/api/fixtures/collect-typescript-jsx/lingui.config.js
deleted file mode 100644
index 56ad10839..000000000
--- a/packages/cli/src/api/fixtures/collect-typescript-jsx/lingui.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- locales: ["en", "cs"]
-}
diff --git a/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-experimental-decorators.tsx b/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-experimental-decorators.tsx
new file mode 100644
index 000000000..7e2ca4de5
--- /dev/null
+++ b/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-experimental-decorators.tsx
@@ -0,0 +1,15 @@
+import { t } from "@lingui/macro"
+
+@Decorator()
+export class TestDecorator {
+ // supports typescript legacy decorator on parameters
+ constructor(@Decorator() param) {}
+
+ @Decorator()
+ prop
+
+ @Decorator()
+ method() {}
+}
+
+t`Message`
diff --git a/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-syntax.tsx b/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-syntax.tsx
index 0b7c3ba2d..f5d97078d 100644
--- a/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-syntax.tsx
+++ b/packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-syntax.tsx
@@ -2,46 +2,46 @@ const jsx = Hello!
// Typescript syntax
function foo(bar: string): string {
- return bar;
+ return bar
}
-const test1: string = "";
+const test1: string = ""
// check parsing different syntax proposals
@Decorator()
export class TestDecorator {
@Decorator()
- prop;
+ prop
@Decorator()
- method() {};
+ method() {}
}
// optional chaining
-const test = foo?.bar?.baz;
+const test = foo?.bar?.baz
class A {
// classProperties
- b = 1;
+ b = 1
// classPrivateProperties
- #b = 1;
+ #b = 1
}
// dynamicImport
-import('./guy').then(a)
+import("./guy").then(a)
// exportNamespaceFrom
export * as ns from "mod"
// nullishCoalescingOperator
-const a = a ?? b;
+const a = a ?? b
// objectRestSpread
-const b = { b, ...c };
+const b = { b, ...c }
// optionalChaining
-const c = a?.b;
+const c = a?.b
// topLevelAwait
-await promise;
+await promise
diff --git a/packages/conf/__typetests__/index.test-d.tsx b/packages/conf/__typetests__/index.test-d.tsx
index 1728317ee..1f582b46e 100644
--- a/packages/conf/__typetests__/index.test-d.tsx
+++ b/packages/conf/__typetests__/index.test-d.tsx
@@ -30,7 +30,7 @@ expectAssignable({
},
extractorParserOptions: {
flow: false,
- decoratorsBeforeExport: false,
+ tsExperimentalDecorators: false,
},
fallbackLocales: {} as FallbackLocales,
format: "po",
diff --git a/packages/conf/src/__snapshots__/index.test.ts.snap b/packages/conf/src/__snapshots__/index.test.ts.snap
index 1eebd8872..bfa7784f3 100644
--- a/packages/conf/src/__snapshots__/index.test.ts.snap
+++ b/packages/conf/src/__snapshots__/index.test.ts.snap
@@ -35,8 +35,8 @@ exports[`@lingui/conf should return default config 1`] = `
minified: true,
},
extractorParserOptions: {
- decoratorsBeforeExport: false,
flow: false,
+ tsExperimentalDecorators: false,
},
fallbackLocales: {
en-gb: en,
diff --git a/packages/conf/src/makeConfig.ts b/packages/conf/src/makeConfig.ts
index f2fe00fc0..548b33448 100644
--- a/packages/conf/src/makeConfig.ts
+++ b/packages/conf/src/makeConfig.ts
@@ -53,7 +53,7 @@ export const defaultConfig: LinguiConfig = {
},
extractorParserOptions: {
flow: false,
- decoratorsBeforeExport: false,
+ tsExperimentalDecorators: false,
},
fallbackLocales: {} as FallbackLocales,
format: "po",
@@ -82,7 +82,7 @@ export const exampleConfig = {
),
extractorParserOptions: {
flow: false,
- decoratorsBeforeExport: false,
+ tsExperimentalDecorators: false,
},
}
diff --git a/packages/conf/src/types.ts b/packages/conf/src/types.ts
index 456a144b4..9434c8082 100644
--- a/packages/conf/src/types.ts
+++ b/packages/conf/src/types.ts
@@ -65,9 +65,12 @@ export type LinguiConfig = {
compileNamespace?: "es" | "ts" | "cjs" | string
extractorParserOptions?: {
/**
- * default true
+ * default false
+ *
+ * By default, standard decorators (Stage3) are applied for TS files
+ * Enable this if you want to use TypesScript's experimental decorators.
*/
- decoratorsBeforeExport?: boolean
+ tsExperimentalDecorators?: boolean
/**
* Enable if you use flow. This will apply Flow syntax to js files
*/
diff --git a/website/docs/ref/conf.md b/website/docs/ref/conf.md
index 0b3fd125c..aa899b4ec 100644
--- a/website/docs/ref/conf.md
+++ b/website/docs/ref/conf.md
@@ -216,10 +216,11 @@ Specify extra options used to parse source files when messages are being extract
```ts
"extractorParserOptions": {
/**
- * default true
- * Use for Stage 3 decorators syntax.
+ * default false
+ * By default, standard decorators (Stage3) are applied for TS files
+ * Enable this if you want to use TypesScript's experimental decorators.
*/
- decoratorsBeforeExport?: boolean
+ tsExperimentalDecorators?: boolean
/**
* default false
* Enable if you use flow. This will apply Flow syntax to files with .js, cjs, .mjs extension.
diff --git a/yarn.lock b/yarn.lock
index fbdd1c9cc..786394c51 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -86,17 +86,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/generator@npm:^7.20.14":
- version: 7.20.14
- resolution: "@babel/generator@npm:7.20.14"
- dependencies:
- "@babel/types": ^7.20.7
- "@jridgewell/gen-mapping": ^0.3.2
- jsesc: ^2.5.1
- checksum: 5f6aa2d86af26e76d276923a5c34191124a119b16ee9ccc34aef654a7dec84fbd7d2daed2e6458a6a06bf87f3661deb77c9fea59b8f67faff5c90793c96d76d6
- languageName: node
- linkType: hard
-
"@babel/generator@npm:^7.20.7":
version: 7.20.7
resolution: "@babel/generator@npm:7.20.7"
@@ -432,7 +421,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/parser@npm:7.20.15, @babel/parser@npm:^7.20.15":
+"@babel/parser@npm:7.20.15":
version: 7.20.15
resolution: "@babel/parser@npm:7.20.15"
bin:
@@ -1486,6 +1475,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.21.0":
+ version: 7.21.0
+ resolution: "@babel/runtime@npm:7.21.0"
+ dependencies:
+ regenerator-runtime: ^0.13.11
+ checksum: 7b33e25bfa9e0e1b9e8828bb61b2d32bdd46b41b07ba7cb43319ad08efc6fda8eb89445193e67d6541814627df0ca59122c0ea795e412b99c5183a0540d338ab
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7, @babel/template@npm:^7.3.3":
version: 7.20.7
resolution: "@babel/template@npm:7.20.7"
@@ -2181,12 +2179,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "@lingui/cli@workspace:packages/cli"
dependencies:
- "@babel/core": ^7.20.12
- "@babel/generator": ^7.20.14
- "@babel/parser": ^7.20.15
- "@babel/plugin-syntax-jsx": ^7.18.6
- "@babel/runtime": ^7.20.13
- "@babel/types": ^7.20.7
+ "@babel/core": ^7.21.0
+ "@babel/generator": ^7.21.1
+ "@babel/parser": ^7.21.2
+ "@babel/runtime": ^7.21.0
+ "@babel/types": ^7.21.2
"@lingui/babel-plugin-extract-messages": 4.0.0-next.1
"@lingui/conf": 4.0.0-next.1
"@lingui/core": 4.0.0-next.1