@lingui/cli 5.9.2 → 6.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/ProgramExit.js +1 -5
- package/dist/api/catalog/extractFromFiles.d.ts +4 -4
- package/dist/api/catalog/extractFromFiles.js +38 -32
- package/dist/api/catalog/getCatalogDependentFiles.d.ts +1 -1
- package/dist/api/catalog/getCatalogDependentFiles.js +8 -47
- package/dist/api/catalog/getCatalogs.d.ts +2 -2
- package/dist/api/catalog/getCatalogs.js +35 -44
- package/dist/api/catalog/getFallbackListForLocale.js +5 -8
- package/dist/api/catalog/getTranslationsForCatalog.d.ts +1 -1
- package/dist/api/catalog/getTranslationsForCatalog.js +9 -13
- package/dist/api/catalog/mergeCatalog.d.ts +3 -3
- package/dist/api/catalog/mergeCatalog.js +13 -21
- package/dist/api/catalog.d.ts +15 -15
- package/dist/api/catalog.js +51 -48
- package/dist/api/compile/compileLocale.d.ts +3 -3
- package/dist/api/compile/compileLocale.js +28 -33
- package/dist/api/compile.js +13 -49
- package/dist/api/extractors/babel.d.ts +2 -2
- package/dist/api/extractors/babel.js +52 -45
- package/dist/api/extractors/index.js +6 -13
- package/dist/api/formats/formatterWrapper.d.ts +2 -2
- package/dist/api/formats/formatterWrapper.js +10 -12
- package/dist/api/formats/index.d.ts +3 -4
- package/dist/api/formats/index.js +5 -44
- package/dist/api/getPathsForCompileWatcher.d.ts +7 -0
- package/dist/api/getPathsForCompileWatcher.js +15 -0
- package/dist/api/getPathsForExtractWatcher.d.ts +8 -0
- package/dist/api/getPathsForExtractWatcher.js +14 -0
- package/dist/api/help.js +5 -7
- package/dist/api/index.d.ts +7 -7
- package/dist/api/index.js +7 -36
- package/dist/api/logger.d.ts +1 -1
- package/dist/api/logger.js +1 -2
- package/dist/api/messages.d.ts +2 -2
- package/dist/api/messages.js +5 -12
- package/dist/api/pseudoLocalize.js +3 -9
- package/dist/api/resolveWorkersOptions.js +3 -9
- package/dist/api/rethrownError.js +2 -5
- package/dist/api/stats.d.ts +3 -2
- package/dist/api/stats.js +7 -16
- package/dist/api/typedPool.d.ts +6 -0
- package/dist/api/typedPool.js +16 -0
- package/dist/api/types.js +1 -2
- package/dist/api/utils.d.ts +2 -2
- package/dist/api/utils.js +24 -41
- package/dist/api/workerLogger.d.ts +2 -2
- package/dist/api/workerLogger.js +2 -8
- package/dist/api/workerPools.d.ts +3 -0
- package/dist/api/workerPools.js +7 -0
- package/dist/extract-experimental/buildIncludeDepsFilter.js +1 -4
- package/dist/extract-experimental/bundleSource.d.ts +3 -2
- package/dist/extract-experimental/bundleSource.js +10 -13
- package/dist/extract-experimental/constants.js +2 -5
- package/dist/extract-experimental/extractFromBundleAndWrite.d.ts +3 -4
- package/dist/extract-experimental/extractFromBundleAndWrite.js +11 -17
- package/dist/extract-experimental/getExperimentalCatalogs.d.ts +4 -3
- package/dist/extract-experimental/getExperimentalCatalogs.js +10 -15
- package/dist/extract-experimental/linguiEsbuildPlugin.js +12 -19
- package/dist/extract-experimental/resolveCatalogPath.d.ts +1 -1
- package/dist/extract-experimental/resolveCatalogPath.js +7 -14
- package/dist/extract-experimental/resolveTemplatePath.js +7 -10
- package/dist/extract-experimental/workers/extractWorker.d.ts +5 -3
- package/dist/extract-experimental/workers/extractWorker.js +7 -10
- package/dist/extract-experimental/workers/extractWorkerWrapper.prod.d.ts +8 -0
- package/dist/extract-experimental/workers/extractWorkerWrapper.prod.js +2 -0
- package/dist/extract-experimental/writeCatalogs.d.ts +2 -2
- package/dist/extract-experimental/writeCatalogs.js +15 -22
- package/dist/index.js +1 -5
- package/dist/lingui-compile.d.ts +1 -1
- package/dist/lingui-compile.js +45 -59
- package/dist/lingui-extract-experimental.d.ts +3 -2
- package/dist/lingui-extract-experimental.js +58 -62
- package/dist/lingui-extract-template.d.ts +5 -4
- package/dist/lingui-extract-template.js +25 -27
- package/dist/lingui-extract.d.ts +3 -4
- package/dist/lingui-extract.js +62 -69
- package/dist/lingui.js +5 -10
- package/dist/services/translationIO/segment-converters.d.ts +1 -1
- package/dist/services/translationIO/segment-converters.js +16 -20
- package/dist/services/translationIO/translationio-api.d.ts +11 -7
- package/dist/services/translationIO/translationio-api.js +2 -19
- package/dist/services/translationIO.d.ts +4 -4
- package/dist/services/translationIO.js +28 -35
- package/dist/workers/compileWorker.d.ts +8 -11
- package/dist/workers/compileWorker.js +30 -36
- package/dist/workers/compileWorkerWrapper.prod.d.ts +7 -0
- package/dist/workers/compileWorkerWrapper.prod.js +2 -0
- package/dist/workers/extractWorker.d.ts +2 -3
- package/dist/workers/extractWorker.js +5 -12
- package/dist/workers/extractWorkerWrapper.prod.d.ts +6 -0
- package/dist/workers/extractWorkerWrapper.prod.js +2 -0
- package/package.json +26 -43
- package/dist/api/extractWorkerPool.d.ts +0 -1
- package/dist/api/extractWorkerPool.js +0 -8
- package/dist/api/extractors/typescript.d.ts +0 -3
- package/dist/api/extractors/typescript.js +0 -11
- package/dist/extract-experimental/getEntryPoints.d.ts +0 -1
- package/dist/extract-experimental/getEntryPoints.js +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LinguiConfigNormalized } from "@lingui/conf";
|
|
2
|
-
import { WorkersOptions } from "./api/resolveWorkersOptions";
|
|
3
|
-
|
|
2
|
+
import { WorkersOptions } from "./api/resolveWorkersOptions.js";
|
|
3
|
+
type CliExtractTemplateOptions = {
|
|
4
4
|
verbose?: boolean;
|
|
5
5
|
files?: string[];
|
|
6
6
|
template?: boolean;
|
|
@@ -10,3 +10,4 @@ export type CliExtractTemplateOptions = {
|
|
|
10
10
|
workersOptions: WorkersOptions;
|
|
11
11
|
};
|
|
12
12
|
export default function command(linguiConfig: LinguiConfigNormalized, options: CliExtractTemplateOptions): Promise<boolean>;
|
|
13
|
+
export {};
|
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const bundleSource_1 = require("./extract-experimental/bundleSource");
|
|
15
|
-
const getEntryPoints_1 = require("./extract-experimental/getEntryPoints");
|
|
16
|
-
const picocolors_1 = __importDefault(require("picocolors"));
|
|
17
|
-
const threads_1 = require("threads");
|
|
18
|
-
const resolveWorkersOptions_1 = require("./api/resolveWorkersOptions");
|
|
19
|
-
const extractFromBundleAndWrite_1 = require("./extract-experimental/extractFromBundleAndWrite");
|
|
20
|
-
async function command(linguiConfig, options) {
|
|
21
|
-
var _a;
|
|
1
|
+
import { program } from "commander";
|
|
2
|
+
import { getConfig } from "@lingui/conf";
|
|
3
|
+
import nodepath from "path";
|
|
4
|
+
import { getFormat } from "./api/formats/index.js";
|
|
5
|
+
import fs from "fs/promises";
|
|
6
|
+
import normalizePath from "normalize-path";
|
|
7
|
+
import { bundleSource } from "./extract-experimental/bundleSource.js";
|
|
8
|
+
import { globSync } from "node:fs";
|
|
9
|
+
import { styleText } from "node:util";
|
|
10
|
+
import { resolveWorkersOptions, } from "./api/resolveWorkersOptions.js";
|
|
11
|
+
import { extractFromBundleAndWrite } from "./extract-experimental/extractFromBundleAndWrite.js";
|
|
12
|
+
import { createExtractExperimentalWorkerPool } from "./api/workerPools.js";
|
|
13
|
+
export default async function command(linguiConfig, options) {
|
|
22
14
|
options.verbose && console.log("Extracting messages from source files…");
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
15
|
+
const extractorConfig = linguiConfig.experimental?.extractor;
|
|
16
|
+
if (!extractorConfig) {
|
|
25
17
|
throw new Error("The configuration for experimental extractor is empty. Please read the docs.");
|
|
26
18
|
}
|
|
27
|
-
console.log(
|
|
19
|
+
console.log(styleText("yellow", [
|
|
28
20
|
"You have using an experimental feature",
|
|
29
21
|
"Experimental features are not covered by semver, and may cause unexpected or broken application behavior." +
|
|
30
22
|
" Use at your own risk.",
|
|
@@ -37,61 +29,65 @@ async function command(linguiConfig, options) {
|
|
|
37
29
|
// sourcemaps itself doesn't allow to have absolute windows path, because they are not URL compatible.
|
|
38
30
|
// that's why we store esbuild bundles in .lingui folder
|
|
39
31
|
const tmpPrefix = ".lingui/";
|
|
40
|
-
await
|
|
41
|
-
const tempDir = await
|
|
42
|
-
await
|
|
43
|
-
const bundleResult = await
|
|
32
|
+
await fs.mkdir(tmpPrefix, { recursive: true });
|
|
33
|
+
const tempDir = await fs.mkdtemp(tmpPrefix);
|
|
34
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
35
|
+
const bundleResult = await bundleSource(linguiConfig, extractorConfig, globSync(extractorConfig.entries), tempDir, linguiConfig.rootDir);
|
|
44
36
|
const stats = [];
|
|
45
37
|
let commandSuccess = true;
|
|
46
38
|
if (options.workersOptions.poolSize) {
|
|
47
|
-
|
|
39
|
+
const resolvedConfigPath = linguiConfig.resolvedConfigPath;
|
|
40
|
+
if (!resolvedConfigPath) {
|
|
48
41
|
throw new Error("Multithreading is only supported when lingui config loaded from file system, not passed by API");
|
|
49
42
|
}
|
|
50
43
|
options.verbose &&
|
|
51
44
|
console.log(`Use worker pool of size ${options.workersOptions.poolSize}`);
|
|
52
|
-
const pool = (
|
|
45
|
+
const pool = createExtractExperimentalWorkerPool({
|
|
46
|
+
poolSize: options.workersOptions.poolSize,
|
|
47
|
+
});
|
|
53
48
|
try {
|
|
54
|
-
|
|
55
|
-
const { entryPoint } = bundleResult.
|
|
56
|
-
pool.
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
await Promise.all(Object.keys(bundleResult.outputs).map(async (outFile) => {
|
|
50
|
+
const { entryPoint } = bundleResult.outputs[outFile];
|
|
51
|
+
const result = await pool.run(resolvedConfigPath, entryPoint, outFile, extractorConfig.output, options.template || false, options.locales || linguiConfig.locales, options.clean || false, options.overwrite || false);
|
|
52
|
+
commandSuccess &&= result.success;
|
|
53
|
+
if (result.success) {
|
|
59
54
|
stats.push({
|
|
60
|
-
entry: (
|
|
61
|
-
content: stat,
|
|
55
|
+
entry: normalizePath(nodepath.relative(linguiConfig.rootDir, entryPoint)),
|
|
56
|
+
content: result.stat,
|
|
62
57
|
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
await pool.completed();
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
66
60
|
}
|
|
67
61
|
finally {
|
|
68
|
-
await pool.
|
|
62
|
+
await pool.destroy();
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
65
|
else {
|
|
72
|
-
const format = await
|
|
73
|
-
for (const outFile of Object.keys(bundleResult.
|
|
74
|
-
const { entryPoint } = bundleResult.
|
|
75
|
-
const
|
|
76
|
-
entryPoint,
|
|
66
|
+
const format = await getFormat(linguiConfig.format, linguiConfig.sourceLocale);
|
|
67
|
+
for (const outFile of Object.keys(bundleResult.outputs)) {
|
|
68
|
+
const { entryPoint } = bundleResult.outputs[outFile];
|
|
69
|
+
const result = await extractFromBundleAndWrite({
|
|
70
|
+
entryPoint: entryPoint,
|
|
77
71
|
bundleFile: outFile,
|
|
78
|
-
outputPattern:
|
|
72
|
+
outputPattern: extractorConfig.output,
|
|
79
73
|
format,
|
|
80
74
|
linguiConfig,
|
|
81
75
|
locales: options.locales || linguiConfig.locales,
|
|
82
|
-
overwrite: options.overwrite,
|
|
83
|
-
clean: options.clean,
|
|
84
|
-
template: options.template,
|
|
85
|
-
});
|
|
86
|
-
commandSuccess && (commandSuccess = success);
|
|
87
|
-
stats.push({
|
|
88
|
-
entry: (0, normalize_path_1.default)(path_1.default.relative(linguiConfig.rootDir, entryPoint)),
|
|
89
|
-
content: stat,
|
|
76
|
+
overwrite: options.overwrite || false,
|
|
77
|
+
clean: options.clean || false,
|
|
78
|
+
template: options.template || false,
|
|
90
79
|
});
|
|
80
|
+
commandSuccess &&= result.success;
|
|
81
|
+
if (result.success) {
|
|
82
|
+
stats.push({
|
|
83
|
+
entry: normalizePath(nodepath.relative(linguiConfig.rootDir, entryPoint)),
|
|
84
|
+
content: result.stat,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
// cleanup temp directory
|
|
94
|
-
await
|
|
90
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
95
91
|
stats
|
|
96
92
|
.sort((a, b) => a.entry.localeCompare(b.entry))
|
|
97
93
|
.forEach(({ entry, content }) => {
|
|
@@ -99,8 +95,8 @@ async function command(linguiConfig, options) {
|
|
|
99
95
|
});
|
|
100
96
|
return commandSuccess;
|
|
101
97
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
98
|
+
if (import.meta.main) {
|
|
99
|
+
program
|
|
104
100
|
.option("--config <path>", "Path to the config file")
|
|
105
101
|
.option("--template", "Extract to template")
|
|
106
102
|
.option("--overwrite", "Overwrite translations for source locale")
|
|
@@ -109,17 +105,17 @@ if (require.main === module) {
|
|
|
109
105
|
.option("--verbose", "Verbose output")
|
|
110
106
|
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
111
107
|
.parse(process.argv);
|
|
112
|
-
const options =
|
|
113
|
-
const config =
|
|
108
|
+
const options = program.opts();
|
|
109
|
+
const config = getConfig({
|
|
114
110
|
configPath: options.config,
|
|
115
111
|
});
|
|
116
112
|
const result = command(config, {
|
|
117
113
|
verbose: options.verbose || false,
|
|
118
114
|
template: options.template,
|
|
119
|
-
locales:
|
|
115
|
+
locales: options.locale?.split(","),
|
|
120
116
|
overwrite: options.overwrite,
|
|
121
117
|
clean: options.clean,
|
|
122
|
-
workersOptions:
|
|
118
|
+
workersOptions: resolveWorkersOptions(options),
|
|
123
119
|
}).then(() => {
|
|
124
120
|
if (!result)
|
|
125
121
|
process.exit(1);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { LinguiConfigNormalized } from "@lingui/conf";
|
|
2
|
-
import { WorkersOptions } from "./api/resolveWorkersOptions";
|
|
3
|
-
|
|
4
|
-
verbose
|
|
2
|
+
import { WorkersOptions } from "./api/resolveWorkersOptions.js";
|
|
3
|
+
type CliExtractTemplateOptions = {
|
|
4
|
+
verbose?: boolean;
|
|
5
5
|
files?: string[];
|
|
6
6
|
workersOptions: WorkersOptions;
|
|
7
7
|
};
|
|
8
|
-
export default function command(config: LinguiConfigNormalized, options:
|
|
8
|
+
export default function command(config: LinguiConfigNormalized, options: CliExtractTemplateOptions): Promise<boolean>;
|
|
9
|
+
export {};
|
|
@@ -1,61 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const api_1 = require("./api");
|
|
11
|
-
const path_1 = __importDefault(require("path"));
|
|
12
|
-
const normalize_path_1 = __importDefault(require("normalize-path"));
|
|
13
|
-
const extractWorkerPool_1 = require("./api/extractWorkerPool");
|
|
14
|
-
const resolveWorkersOptions_1 = require("./api/resolveWorkersOptions");
|
|
15
|
-
async function command(config, options) {
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { getConfig } from "@lingui/conf";
|
|
4
|
+
import { getCatalogs } from "./api/index.js";
|
|
5
|
+
import nodepath from "path";
|
|
6
|
+
import normalizePath from "normalize-path";
|
|
7
|
+
import { createExtractWorkerPool, } from "./api/workerPools.js";
|
|
8
|
+
import { resolveWorkersOptions, } from "./api/resolveWorkersOptions.js";
|
|
9
|
+
export default async function command(config, options) {
|
|
16
10
|
options.verbose && console.log("Extracting messages from source files…");
|
|
17
|
-
const catalogs = await
|
|
11
|
+
const catalogs = await getCatalogs(config);
|
|
18
12
|
const catalogStats = {};
|
|
19
13
|
let commandSuccess = true;
|
|
20
14
|
let workerPool;
|
|
21
15
|
if (options.workersOptions.poolSize) {
|
|
22
16
|
options.verbose &&
|
|
23
17
|
console.log(`Use worker pool of size ${options.workersOptions.poolSize}`);
|
|
24
|
-
workerPool =
|
|
18
|
+
workerPool = createExtractWorkerPool(options.workersOptions);
|
|
25
19
|
}
|
|
26
20
|
try {
|
|
27
21
|
await Promise.all(catalogs.map(async (catalog) => {
|
|
28
|
-
const result = await catalog.makeTemplate(
|
|
22
|
+
const result = await catalog.makeTemplate({
|
|
23
|
+
...options,
|
|
24
|
+
orderBy: config.orderBy,
|
|
25
|
+
workerPool,
|
|
26
|
+
});
|
|
29
27
|
if (result) {
|
|
30
|
-
catalogStats[(
|
|
28
|
+
catalogStats[normalizePath(nodepath.relative(config.rootDir, catalog.templateFile))] = Object.keys(result).length;
|
|
31
29
|
}
|
|
32
|
-
commandSuccess
|
|
30
|
+
commandSuccess &&= Boolean(result);
|
|
33
31
|
}));
|
|
34
32
|
}
|
|
35
33
|
finally {
|
|
36
34
|
if (workerPool) {
|
|
37
|
-
await workerPool.
|
|
35
|
+
await workerPool.destroy();
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
Object.entries(catalogStats).forEach(([key, value]) => {
|
|
41
|
-
console.log(`Catalog statistics for ${
|
|
39
|
+
console.log(`Catalog statistics for ${styleText("bold", key)}: ${styleText("green", String(value))} messages`);
|
|
42
40
|
console.log();
|
|
43
41
|
});
|
|
44
42
|
return commandSuccess;
|
|
45
43
|
}
|
|
46
|
-
if (
|
|
47
|
-
|
|
44
|
+
if (import.meta.main) {
|
|
45
|
+
program
|
|
48
46
|
.option("--config <path>", "Path to the config file")
|
|
49
47
|
.option("--verbose", "Verbose output")
|
|
50
48
|
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
51
49
|
.parse(process.argv);
|
|
52
|
-
const options =
|
|
53
|
-
const config =
|
|
50
|
+
const options = program.opts();
|
|
51
|
+
const config = getConfig({
|
|
54
52
|
configPath: options.config,
|
|
55
53
|
});
|
|
56
54
|
const result = command(config, {
|
|
57
55
|
verbose: options.verbose || false,
|
|
58
|
-
workersOptions:
|
|
56
|
+
workersOptions: resolveWorkersOptions(options),
|
|
59
57
|
}).then(() => {
|
|
60
58
|
if (!result)
|
|
61
59
|
process.exit(1);
|
package/dist/lingui-extract.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { LinguiConfigNormalized } from "@lingui/conf";
|
|
2
|
-
import { WorkersOptions } from "./api/resolveWorkersOptions";
|
|
2
|
+
import { WorkersOptions } from "./api/resolveWorkersOptions.js";
|
|
3
3
|
export type CliExtractOptions = {
|
|
4
4
|
verbose: boolean;
|
|
5
5
|
files?: string[];
|
|
6
6
|
clean: boolean;
|
|
7
7
|
overwrite: boolean;
|
|
8
|
-
locale
|
|
9
|
-
prevFormat: string | null;
|
|
8
|
+
locale?: string[];
|
|
10
9
|
watch?: boolean;
|
|
11
10
|
workersOptions: WorkersOptions;
|
|
12
11
|
};
|
|
13
|
-
export default function command(config: LinguiConfigNormalized, options:
|
|
12
|
+
export default function command(config: LinguiConfigNormalized, options: CliExtractOptions): Promise<boolean>;
|
package/dist/lingui-extract.js
CHANGED
|
@@ -1,54 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const extractWorkerPool_1 = require("./api/extractWorkerPool");
|
|
19
|
-
const ms_1 = __importDefault(require("ms"));
|
|
20
|
-
async function command(config, options) {
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import chokidar from "chokidar";
|
|
3
|
+
import { program } from "commander";
|
|
4
|
+
import nodepath from "path";
|
|
5
|
+
import { getConfig } from "@lingui/conf";
|
|
6
|
+
import { getCatalogs } from "./api/index.js";
|
|
7
|
+
import { printStats } from "./api/stats.js";
|
|
8
|
+
import { helpRun } from "./api/help.js";
|
|
9
|
+
import ora from "ora";
|
|
10
|
+
import normalizePath from "normalize-path";
|
|
11
|
+
import { resolveWorkersOptions, } from "./api/resolveWorkersOptions.js";
|
|
12
|
+
import { createExtractWorkerPool, } from "./api/workerPools.js";
|
|
13
|
+
import ms from "ms";
|
|
14
|
+
import { getPathsForExtractWatcher } from "./api/getPathsForExtractWatcher.js";
|
|
15
|
+
import { glob } from "node:fs/promises";
|
|
16
|
+
import micromatch from "micromatch";
|
|
17
|
+
export default async function command(config, options) {
|
|
21
18
|
const startTime = Date.now();
|
|
22
19
|
options.verbose && console.log("Extracting messages from source files…");
|
|
23
|
-
const catalogs = await
|
|
20
|
+
const catalogs = await getCatalogs(config);
|
|
24
21
|
const catalogStats = {};
|
|
25
22
|
let commandSuccess = true;
|
|
26
23
|
let workerPool;
|
|
27
24
|
// important to initialize ora before worker pool, otherwise it cause
|
|
28
25
|
// MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 unpipe listeners added to [WriteStream]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit
|
|
29
26
|
// when workers >= 10
|
|
30
|
-
const spinner = (
|
|
27
|
+
const spinner = ora();
|
|
31
28
|
if (options.workersOptions.poolSize) {
|
|
32
29
|
options.verbose &&
|
|
33
30
|
console.log(`Use worker pool of size ${options.workersOptions.poolSize}`);
|
|
34
|
-
workerPool =
|
|
31
|
+
workerPool = createExtractWorkerPool(options.workersOptions);
|
|
35
32
|
}
|
|
36
33
|
spinner.start();
|
|
37
34
|
let extractionResult;
|
|
38
35
|
try {
|
|
39
36
|
extractionResult = await Promise.all(catalogs.map(async (catalog) => {
|
|
40
|
-
const result = await catalog.make(
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
const result = await catalog.make({
|
|
38
|
+
...options,
|
|
39
|
+
orderBy: config.orderBy,
|
|
40
|
+
workerPool,
|
|
41
|
+
});
|
|
42
|
+
catalogStats[normalizePath(nodepath.relative(config.rootDir, catalog.path))] = result || {};
|
|
43
|
+
commandSuccess &&= Boolean(result);
|
|
43
44
|
return { catalog, messagesByLocale: result };
|
|
44
45
|
}));
|
|
45
46
|
}
|
|
46
47
|
finally {
|
|
47
48
|
if (workerPool) {
|
|
48
|
-
await workerPool.
|
|
49
|
+
await workerPool.destroy();
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
|
-
const doneMsg = `Done in ${(
|
|
52
|
+
const doneMsg = `Done in ${ms(Date.now() - startTime)}`;
|
|
52
53
|
if (commandSuccess) {
|
|
53
54
|
spinner.succeed(doneMsg);
|
|
54
55
|
}
|
|
@@ -57,20 +58,24 @@ async function command(config, options) {
|
|
|
57
58
|
}
|
|
58
59
|
Object.entries(catalogStats).forEach(([key, value]) => {
|
|
59
60
|
console.log(`Catalog statistics for ${key}: `);
|
|
60
|
-
console.log(
|
|
61
|
+
console.log(printStats(config, value).toString());
|
|
61
62
|
console.log();
|
|
62
63
|
});
|
|
63
64
|
if (!options.watch) {
|
|
64
|
-
console.log(`(Use "${
|
|
65
|
-
console.log(`(Use "${
|
|
65
|
+
console.log(`(Use "${styleText("yellow", helpRun("extract"))}" to update catalogs with new messages.)`);
|
|
66
|
+
console.log(`(Use "${styleText("yellow", helpRun("compile"))}" to compile catalogs for production. Alternatively, use bundler plugins: https://lingui.dev/ref/cli#compiling-catalogs-in-ci)`);
|
|
66
67
|
}
|
|
67
68
|
// If service key is present in configuration, synchronize with cloud translation platform
|
|
68
|
-
if (
|
|
69
|
-
config.service.name &&
|
|
70
|
-
config.service.name.length) {
|
|
69
|
+
if (config.service?.name?.length) {
|
|
71
70
|
const moduleName = config.service.name.charAt(0).toLowerCase() + config.service.name.slice(1);
|
|
71
|
+
const services = {
|
|
72
|
+
translationIO: () => import(`./services/translationIO.js`),
|
|
73
|
+
};
|
|
74
|
+
if (!services[moduleName]) {
|
|
75
|
+
console.error(`Can't load service module ${moduleName}`);
|
|
76
|
+
}
|
|
72
77
|
try {
|
|
73
|
-
const module =
|
|
78
|
+
const module = services[moduleName]();
|
|
74
79
|
await module
|
|
75
80
|
.default(config, options, extractionResult)
|
|
76
81
|
.then(console.log)
|
|
@@ -82,8 +87,8 @@ async function command(config, options) {
|
|
|
82
87
|
}
|
|
83
88
|
return commandSuccess;
|
|
84
89
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
90
|
+
if (import.meta.main) {
|
|
91
|
+
program
|
|
87
92
|
.option("--config <path>", "Path to the config file")
|
|
88
93
|
.option("--locale <locale, [...]>", "Only extract the specified locales", (value) => {
|
|
89
94
|
return value
|
|
@@ -96,30 +101,18 @@ if (require.main === module) {
|
|
|
96
101
|
.option("--clean", "Remove obsolete translations")
|
|
97
102
|
.option("--debounce <delay>", "Debounces extraction for given amount of milliseconds")
|
|
98
103
|
.option("--verbose", "Verbose output")
|
|
99
|
-
.option("--convert-from <format>", "Convert from previous format of message catalogs")
|
|
100
104
|
.option("--watch", "Enables Watch Mode")
|
|
101
105
|
.parse(process.argv);
|
|
102
|
-
const options =
|
|
103
|
-
const config =
|
|
106
|
+
const options = program.opts();
|
|
107
|
+
const config = getConfig({
|
|
104
108
|
configPath: options.config,
|
|
105
109
|
});
|
|
106
110
|
let hasErrors = false;
|
|
107
|
-
const prevFormat = options.convertFrom;
|
|
108
|
-
if (prevFormat && config.format === prevFormat) {
|
|
109
|
-
hasErrors = true;
|
|
110
|
-
console.error("Trying to migrate message catalog to the same format");
|
|
111
|
-
console.error(`Set ${picocolors_1.default.bold("new")} format in LinguiJS configuration\n` +
|
|
112
|
-
` and ${picocolors_1.default.bold("previous")} format using --convert-from option.`);
|
|
113
|
-
console.log();
|
|
114
|
-
console.log(`Example: Convert from lingui format to minimal`);
|
|
115
|
-
console.log(picocolors_1.default.yellow((0, help_1.helpRun)(`extract --convert-from lingui`)));
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
111
|
if (options.locale) {
|
|
119
112
|
const missingLocale = options.locale.find((l) => !config.locales.includes(l));
|
|
120
113
|
if (missingLocale) {
|
|
121
114
|
hasErrors = true;
|
|
122
|
-
console.error(`Locale ${
|
|
115
|
+
console.error(`Locale ${styleText("bold", missingLocale)} does not exist.`);
|
|
123
116
|
console.error();
|
|
124
117
|
}
|
|
125
118
|
}
|
|
@@ -132,9 +125,8 @@ if (require.main === module) {
|
|
|
132
125
|
overwrite: options.watch || options.overwrite || false,
|
|
133
126
|
locale: options.locale,
|
|
134
127
|
watch: options.watch || false,
|
|
135
|
-
files:
|
|
136
|
-
|
|
137
|
-
workersOptions: (0, resolveWorkersOptions_1.resolveWorkersOptions)(options),
|
|
128
|
+
files: filePath?.length ? filePath : undefined,
|
|
129
|
+
workersOptions: resolveWorkersOptions(options),
|
|
138
130
|
});
|
|
139
131
|
};
|
|
140
132
|
const changedPaths = new Set();
|
|
@@ -147,7 +139,7 @@ if (require.main === module) {
|
|
|
147
139
|
previousExtract = previousExtract.then(() => extract(filePath));
|
|
148
140
|
return previousExtract;
|
|
149
141
|
}
|
|
150
|
-
filePath
|
|
142
|
+
filePath?.forEach((path) => changedPaths.add(path));
|
|
151
143
|
// CLear the previous timer if there is any, and schedule the next
|
|
152
144
|
debounceTimer && clearTimeout(debounceTimer);
|
|
153
145
|
debounceTimer = setTimeout(async () => {
|
|
@@ -158,21 +150,22 @@ if (require.main === module) {
|
|
|
158
150
|
};
|
|
159
151
|
// Check if Watch Mode is enabled
|
|
160
152
|
if (options.watch) {
|
|
161
|
-
console.info(
|
|
153
|
+
console.info(styleText("bold", "Initializing Watch Mode..."));
|
|
162
154
|
(async function initWatch() {
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
155
|
+
const { paths, ignored } = await getPathsForExtractWatcher(config);
|
|
156
|
+
const matchedPaths = [];
|
|
157
|
+
for await (const path of glob(paths)) {
|
|
158
|
+
matchedPaths.push(path);
|
|
159
|
+
}
|
|
160
|
+
const watcher = chokidar.watch(matchedPaths, {
|
|
161
|
+
ignored: [
|
|
162
|
+
"/(^|[/\\])../",
|
|
163
|
+
(path) => micromatch.any(path, ignored),
|
|
164
|
+
],
|
|
172
165
|
persistent: true,
|
|
173
166
|
});
|
|
174
167
|
const onReady = () => {
|
|
175
|
-
console.info(
|
|
168
|
+
console.info(styleText(["green", "bold"], "Watcher is ready!"));
|
|
176
169
|
watcher
|
|
177
170
|
.on("add", (path) => dispatchExtract([path]))
|
|
178
171
|
.on("change", (path) => dispatchExtract([path]));
|
|
@@ -180,10 +173,10 @@ if (require.main === module) {
|
|
|
180
173
|
watcher.on("ready", () => onReady());
|
|
181
174
|
})();
|
|
182
175
|
}
|
|
183
|
-
else if (
|
|
176
|
+
else if (program.args) {
|
|
184
177
|
// this behaviour occurs when we extract files by his name
|
|
185
178
|
// for ex: lingui extract src/app, this will extract only files included in src/app
|
|
186
|
-
extract(
|
|
179
|
+
extract(program.args).then((result) => {
|
|
187
180
|
if (!result)
|
|
188
181
|
process.exit(1);
|
|
189
182
|
});
|
package/dist/lingui.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const node_fs_1 = require("node:fs");
|
|
9
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const packageJson = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.resolve(__dirname, "../package.json"), "utf8"));
|
|
11
|
-
commander_1.program
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
const packageJson = JSON.parse(readFileSync(path.resolve(import.meta.dirname, "../package.json"), "utf8"));
|
|
6
|
+
program
|
|
12
7
|
.version(packageJson.version)
|
|
13
8
|
.command("extract [files...]", "Extracts messages from source files")
|
|
14
9
|
.command("extract-experimental", "Extracts messages from source files traversing dependency tree")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { MessageType } from "@lingui/conf";
|
|
2
|
-
import { TranslationIoSegment } from "./translationio-api";
|
|
2
|
+
import { TranslationIoSegment } from "./translationio-api.js";
|
|
3
3
|
export declare function createSegmentFromLinguiItem(key: string, item: MessageType): TranslationIoSegment;
|
|
4
4
|
export declare function createLinguiItemFromSegment(segment: TranslationIoSegment): readonly [string, MessageType];
|