Skip to content

Commit

Permalink
feat: configurable and extendable extractors with Lingui config (#1065)
Browse files Browse the repository at this point in the history
  • Loading branch information
semoal authored May 18, 2021
1 parent ff7a235 commit 263ee59
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 24 deletions.
24 changes: 24 additions & 0 deletions docs/ref/conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Default config:
"fallbackLocales": {},
"format": "po",
"locales": [],
"extractors": ["babel"],
"orderBy": "messageId",
"pseudoLocale": "",
"rootDir": ".",
Expand Down Expand Up @@ -506,3 +507,26 @@ providing custom translation.
The difference between :conf:`fallbackLocales` and :conf:`sourceLocale` is that
:conf:`fallbackLocales` is used in translation, while :conf:`sourceLocale` is
used for the message ID.

extractors
------------

Default: ``[babel]``

Extractors it's the way to customize which extractor you want for your codebase, a long time ago Babel wasn't ready yet to work with Typescript,
so we added two extractors as default ``[babel, typescript]``, but right now Babel already works good with Typescript so isn't a requirement anymore to compile two times the same code.

Anyway, if you want to use the typescript extractor in conjuntion with babel you can do:

.. code-block:: js
{
"extractors": [
require.resolve("@lingui/cli/api/extractors/babel"),
require.resolve("@lingui/cli/api/extractors/typescript"),
]
}
Of course you can build your own extractor, take a look to babel and typescript extractors to see how you should do it, but basically exports two methods:
- match: regex to a filename extension, should return true|false
- extract: is the responsible of transforming the code and using @lingui/babel-plugin-extract-messages
2 changes: 2 additions & 0 deletions packages/cli/src/api/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ export class Catalog {
extract(filename, tmpDir, {
verbose: options.verbose,
babelOptions: this.config.extractBabelOptions,
// @ts-ignore
extractors: options.extractors,
projectType: options.projectType,
})
)
Expand Down
100 changes: 98 additions & 2 deletions packages/cli/src/api/extract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,20 @@ describe("extract", function () {
})
})

afterEach(() => {
jest.clearAllMocks()
})
afterAll(() => {
mockFs.restore()
})

it("should traverse directory and call extractors", function () {
extract(["src"], "locale", {
ignore: ["forbidden"],
extractors: [
babel,
typescript
],
babelOptions: {},
})

Expand Down Expand Up @@ -92,8 +99,8 @@ describe("extract", function () {
)

const extractArgs = [
"locale",
{ babelOptions: {}, ignore: ["forbidden"]}
"locale",
{ extractors: [babel, typescript], babelOptions: {}, ignore: ["forbidden"]}
]
expect(babel.extract).toHaveBeenCalledWith(
path.join("src", "components", "Babel.js"),
Expand Down Expand Up @@ -145,6 +152,95 @@ describe("extract", function () {
...extractArgs
)
})

it("by default the traverse directory only uses babel", function () {
extract(["src"], "locale", {
ignore: ["forbidden"],
babelOptions: {},
})

expect(typescript.match).not.toHaveBeenCalledWith(
path.join("src", "components", "Typescript.ts")
)
expect(babel.match).toHaveBeenCalledWith(
path.join("src", "components", "Babel.js")
)
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"),
...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"),
...extractArgs
)

expect(typescript.extract).not.toHaveBeenCalledWith(
path.join("src", "components", "Babel.js"),
...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).not.toHaveBeenCalledWith(
path.join("src", "components", "Typescript.ts"),
...extractArgs
)
})
})

describe("collect", function () {
Expand Down
19 changes: 4 additions & 15 deletions packages/cli/src/api/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import * as R from "ramda"

import { prettyOrigin } from "./utils"

import * as extractors from "./extractors"
import { ExtractorType } from "./extractors"

import cliExtractor, { ExtractorType } from "./extractors"

type ExtractOptions = {
ignore?: Array<string>
verbose?: boolean
extractors?: ExtractorType[]
projectType?: string
babelOptions?: Object
}
Expand Down Expand Up @@ -44,7 +43,7 @@ export function extract(
targetPath: string,
options: ExtractOptions = {}
) {
const { ignore = [], verbose = false } = options
const { ignore = [] } = options
const ignorePattern = ignore.length ? new RegExp(ignore.join("|"), "i") : null

srcPaths.forEach((srcFilename) => {
Expand All @@ -64,17 +63,7 @@ export function extract(
return
}

R.values(extractors).some((ext: ExtractorType) => {
if (!ext.match || !ext.match(srcFilename)) return false

let spinner
if (verbose) spinner = ora().start(srcFilename)

ext.extract(srcFilename, targetPath, options)
if (verbose && spinner) spinner.succeed()

return true
})
cliExtractor(srcFilename, targetPath, options)
})
}

Expand Down
12 changes: 5 additions & 7 deletions packages/cli/src/api/extractors/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import ora from "ora"
import babel from "./babel"
import typescript from "./typescript"
import * as R from "ramda"

const extractors = { babel, typescript }

const DEFAULT_EXTRACTORS: ExtractorType[] = [babel]

export type BabelOptions = {
plugins?: Array<string>
Expand All @@ -14,6 +11,7 @@ export type BabelOptions = {
export type ExtractOptions = {
verbose?: boolean
projectType?: string
extractors?: ExtractorType[]
babelOptions?: BabelOptions
}

Expand All @@ -27,7 +25,9 @@ export default function extract(
targetPath: string,
options: ExtractOptions
): boolean {
return R.values(extractors).some((ext: ExtractorType) => {
const extractorsToExtract = options.extractors ?? DEFAULT_EXTRACTORS

return extractorsToExtract.some((ext) => {
if (!ext.match(filename)) return false

let spinner
Expand All @@ -48,5 +48,3 @@ export default function extract(
return true
})
}

export { babel, typescript }
1 change: 1 addition & 0 deletions packages/cli/src/lingui-extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function command(
catalog.make({
...options,
orderBy: config.orderBy,
extractors: config.extractors,
projectType: detect(),
})

Expand Down
6 changes: 6 additions & 0 deletions packages/conf/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ export type DefaultLocaleObject = {

export declare type FallbackLocales = LocaleObject | DefaultLocaleObject

declare type ExtractorType = {
match(filename: string): boolean;
extract(filename: string, targetDir: string, options?: any): void;
}

export declare type LinguiConfig = {
catalogs: CatalogConfig[];
compileNamespace: "es" | "cjs" | "ts" | string;
extractBabelOptions: Record<string, unknown>;
compilerBabelOptions: GeneratorOptions;
fallbackLocales: FallbackLocales;
format: CatalogFormat;
extractors?: ExtractorType[];
prevFormat: CatalogFormat;
formatOptions: CatalogFormatOptions;
localeDir: string;
Expand Down
6 changes: 6 additions & 0 deletions packages/conf/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@ export type FallbackLocales = LocaleObject | DefaultLocaleObject | false

type ModuleSource = [string, string?]

type ExtractorType = {
match(filename: string): boolean
extract(filename: string, targetDir: string, options?: any): void
}

export type LinguiConfig = {
catalogs: CatalogConfig[]
compileNamespace: "es" | "ts" | "cjs" | string
extractBabelOptions: Record<string, unknown>
compilerBabelOptions: GeneratorOptions
fallbackLocales?: FallbackLocales
extractors?: ExtractorType[]
format: CatalogFormat
formatOptions: CatalogFormatOptions
locales: string[]
Expand Down

1 comment on commit 263ee59

@vercel
Copy link

@vercel vercel bot commented on 263ee59 May 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.