Skip to content

Commit a4f90ee

Browse files
authored
feat: --watch mode for extract and compile (#974)
1 parent a584194 commit a4f90ee

5 files changed

Lines changed: 139 additions & 26 deletions

File tree

docs/ref/cli.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Commands
4444
``extract``
4545
-----------
4646

47-
.. lingui-cli:: extract [files...] [--clean] [--overwrite] [--format <format>] [--locale <locale>] [--convert-from <format>] [--verbose]
47+
.. lingui-cli:: extract [files...] [--clean] [--overwrite] [--format <format>] [--locale <locale>] [--convert-from <format>] [--verbose] [--watch]
4848

4949
This command extracts messages from source files and creates a message catalog for
5050
each language using the following steps:
@@ -101,6 +101,14 @@ Convert message catalogs from previous format (see :conf:`format` option).
101101

102102
Prints additional information.
103103

104+
.. lingui-cli-option:: --watch
105+
106+
Watch mode.
107+
108+
Watches only for changes in files in paths defined in config file or in the command itself.
109+
110+
Remember to use this only in development as this command do not cleans obsolete translations.
111+
104112
``extract-template``
105113
--------------------
106114

@@ -115,7 +123,7 @@ Prints additional information.
115123
``compile``
116124
-----------
117125

118-
.. lingui-cli:: compile [--strict] [--format <format>] [--verbose] [--namespace <namespace>]
126+
.. lingui-cli:: compile [--strict] [--format <format>] [--verbose] [--namespace <namespace>] [--watch]
119127

120128
This command compiles message catalogs in :conf:`localeDir` and outputs
121129
minified Javascript files. Each message is replaced with a function
@@ -144,3 +152,9 @@ global configuration).
144152

145153
Is the same as using :conf:`compileNamespace` with the value "ts".
146154
Generates a {compiledFile}.d.ts and the compiled file is generated using the extension .ts
155+
156+
.. lingui-cli-option:: --watch
157+
158+
Watch mode.
159+
160+
Watches only for changes in locale files in your defined locale catalogs. For ex. ``locales\en\messages.po``

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"babel-plugin-macros": "^2.8.0",
4444
"bcp-47": "^1.0.7",
4545
"chalk": "^4.1.0",
46+
"chokidar": "3.5.1",
4647
"cli-table": "^0.3.1",
4748
"commander": "^6.1.0",
4849
"date-fns": "^2.16.1",

packages/cli/src/lingui-compile.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import chalk from "chalk"
2+
import chokidar from "chokidar"
23
import fs from "fs"
34
import * as R from "ramda"
45
import program from "commander"
@@ -129,6 +130,7 @@ if (require.main === module) {
129130
"--namespace <namespace>",
130131
"Specify namespace for compiled bundle. Ex: cjs(default) -> module.exports, es -> export, window.test -> window.test"
131132
)
133+
.option("--watch", "Enables Watch Mode")
132134
.on("--help", function () {
133135
console.log("\n Examples:\n")
134136
console.log(
@@ -153,16 +155,46 @@ if (require.main === module) {
153155
config.format = program.format
154156
}
155157

156-
const results = command(config, {
157-
verbose: program.verbose || false,
158+
const compile = () => command(config, {
159+
verbose: program.watch || program.verbose || false,
158160
allowEmpty: !program.strict,
159161
typescript: program.typescript || config.compileNamespace === "ts" || false,
160162
namespace: program.namespace, // we want this to be undefined if user does not specify so default can be used
161163
})
162164

163-
if (!results) {
164-
process.exit(1)
165-
}
165+
// Check if Watch Mode is enabled
166+
if (program.watch) {
167+
const NAME = "{name}"
168+
const LOCALE = "{locale}"
169+
170+
console.info(chalk.bold("Initializing Watch Mode..."))
171+
172+
const catalogs = getCatalogs(config);
173+
let paths = [];
174+
175+
config.locales.forEach((locale) => {
176+
catalogs.forEach((catalog) => {
177+
paths.push(`${catalog.path.replace(LOCALE, locale).replace(NAME, "*")}.${config.format}`)
178+
})
179+
})
180+
181+
const watcher = chokidar.watch(paths, {
182+
persistent: true,
183+
});
166184

167-
console.log("Done!")
185+
const onReady = () => {
186+
console.info(chalk.green.bold("Watcher is ready!"))
187+
watcher.on('add', () => compile()).on('change', () => compile());
188+
};
189+
190+
watcher.on('ready', () => onReady());
191+
} else {
192+
const results = compile();
193+
194+
if (!results) {
195+
process.exit(1)
196+
}
197+
198+
console.log("Done!")
199+
}
168200
}

packages/cli/src/lingui-extract.ts

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import chalk from "chalk"
2+
import chokidar from "chokidar"
23
import program from "commander"
34

45
import { getConfig, LinguiConfig } from "@lingui/conf"
@@ -15,6 +16,7 @@ export type CliExtractOptions = {
1516
overwrite: boolean
1617
locale: string
1718
prevFormat: string | null
19+
watch?: boolean
1820
}
1921

2022
export default function command(
@@ -33,6 +35,7 @@ export default function command(
3335
process.env.LINGUI_EXTRACT = "1"
3436

3537
options.verbose && console.error("Extracting messages from source files…")
38+
3639
const catalogs = getCatalogs(config)
3740
const catalogStats: { [path: string]: AllCatalogsType } = {}
3841
catalogs.forEach((catalog) => {
@@ -51,16 +54,19 @@ export default function command(
5154
console.log()
5255
})
5356

54-
console.error(
55-
`(use "${chalk.yellow(
56-
helpRun("extract")
57-
)}" to update catalogs with new messages)`
58-
)
59-
console.error(
60-
`(use "${chalk.yellow(
61-
helpRun("compile")
62-
)}" to compile catalogs for production)`
63-
)
57+
if (!options.watch) {
58+
console.error(
59+
`(use "${chalk.yellow(
60+
helpRun("extract")
61+
)}" to update catalogs with new messages)`
62+
)
63+
console.error(
64+
`(use "${chalk.yellow(
65+
helpRun("compile")
66+
)}" to compile catalogs for production)`
67+
)
68+
}
69+
6470
return true
6571
}
6672

@@ -75,6 +81,7 @@ if (require.main === module) {
7581
"--convert-from <format>",
7682
"Convert from previous format of message catalogs"
7783
)
84+
.option("--watch", "Enables Watch Mode")
7885
// Obsolete options
7986
.option(
8087
"--babelOptions",
@@ -127,14 +134,46 @@ if (require.main === module) {
127134
}
128135

129136
if (hasErrors) process.exit(1)
137+
138+
const extract = (filePath?: string) =>
139+
command(config, {
140+
verbose: program.watch || program.verbose || false,
141+
clean: program.watch ? false : program.clean || false,
142+
overwrite: program.watch || program.overwrite || false,
143+
locale: program.locale,
144+
watch: program.watch || false,
145+
files: filePath ? [filePath] : undefined,
146+
prevFormat,
147+
})
148+
130149

131-
const result = command(config, {
132-
verbose: program.verbose || false,
133-
clean: program.clean || false,
134-
overwrite: program.overwrite || false,
135-
locale: program.locale,
136-
prevFormat,
137-
})
150+
// Check if Watch Mode is enabled
151+
if (program.watch) {
152+
console.info(chalk.bold("Initializing Watch Mode..."))
153+
154+
const catalogs = getCatalogs(config)
155+
let paths = [];
156+
let ignored = [];
138157

139-
if (!result) process.exit(1)
158+
catalogs.forEach((catalog) => {
159+
paths.push(...catalog.include);
160+
ignored.push(...catalog.exclude);
161+
})
162+
163+
const watcher = chokidar.watch(paths, {
164+
ignored: ['/(^|[\/\\])\../', ...ignored],
165+
persistent: true,
166+
});
167+
168+
const onReady = () => {
169+
console.info(chalk.green.bold("Watcher is ready!"))
170+
watcher.on('add', (path) => extract(path)).on('change', (path) => extract(path));
171+
};
172+
173+
watcher.on('ready', () => onReady());
174+
} else {
175+
const result = extract();
176+
177+
if (!result) process.exit(1)
178+
}
140179
}

yarn.lock

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4282,6 +4282,21 @@ chokidar@^3.4.1:
42824282
optionalDependencies:
42834283
fsevents "~2.1.2"
42844284

4285+
chokidar@^3.5.1:
4286+
version "3.5.1"
4287+
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
4288+
integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
4289+
dependencies:
4290+
anymatch "~3.1.1"
4291+
braces "~3.0.2"
4292+
glob-parent "~5.1.0"
4293+
is-binary-path "~2.1.0"
4294+
is-glob "~4.0.1"
4295+
normalize-path "~3.0.0"
4296+
readdirp "~3.5.0"
4297+
optionalDependencies:
4298+
fsevents "~2.3.1"
4299+
42854300
chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2:
42864301
version "1.1.4"
42874302
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
@@ -6148,6 +6163,11 @@ fsevents@^2.1.2, fsevents@~2.1.2:
61486163
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
61496164
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
61506165

6166+
fsevents@~2.3.1:
6167+
version "2.3.2"
6168+
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
6169+
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
6170+
61516171
ftp@~0.3.10:
61526172
version "0.3.10"
61536173
resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d"
@@ -10427,6 +10447,13 @@ readdirp@~3.4.0:
1042710447
dependencies:
1042810448
picomatch "^2.2.1"
1042910449

10450+
readdirp@~3.5.0:
10451+
version "3.5.0"
10452+
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
10453+
integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
10454+
dependencies:
10455+
picomatch "^2.2.1"
10456+
1043010457
redent@^1.0.0:
1043110458
version "1.0.0"
1043210459
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"

0 commit comments

Comments
 (0)