@lingui/cli 6.7.0 → 6.8.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/catalog/extractFromFiles.d.ts +3 -3
- package/dist/api/catalog/extractFromFiles.js +15 -7
- package/dist/api/catalog/getTranslationsForCatalog.d.ts +11 -2
- package/dist/api/catalog/getTranslationsForCatalog.js +61 -28
- package/dist/api/catalog/mergeCatalog.js +3 -1
- package/dist/api/catalog/translations.d.ts +16 -0
- package/dist/api/catalog/translations.js +35 -0
- package/dist/api/catalog.d.ts +0 -1
- package/dist/api/catalog.js +4 -58
- package/dist/api/check/index.d.ts +8 -0
- package/dist/api/check/index.js +39 -0
- package/dist/api/check/missing.d.ts +2 -0
- package/dist/api/check/missing.js +56 -0
- package/dist/api/check/sync.d.ts +2 -0
- package/dist/api/check/sync.js +96 -0
- package/dist/api/check/types.d.ts +62 -0
- package/dist/api/check/types.js +13 -0
- package/dist/api/compile/compileLocale.js +6 -7
- package/dist/api/extractors/index.d.ts +1 -4
- package/dist/api/extractors/index.js +3 -10
- package/dist/api/formats/formatterWrapper.d.ts +1 -0
- package/dist/api/formats/formatterWrapper.js +12 -5
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +1 -1
- package/dist/api/messages.d.ts +8 -2
- package/dist/api/messages.js +29 -2
- package/dist/api/resolveWorkersOptions.js +17 -3
- package/dist/api/runBounded.d.ts +1 -0
- package/dist/api/runBounded.js +13 -0
- package/dist/api/utils.d.ts +5 -0
- package/dist/api/utils.js +7 -0
- package/dist/api/workerPools.d.ts +2 -0
- package/dist/api/workerPools.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -0
- package/dist/lingui-check.d.ts +6 -0
- package/dist/lingui-check.js +137 -0
- package/dist/lingui-compile.js +6 -6
- package/dist/lingui-extract-experimental.js +1 -1
- package/dist/lingui-extract-template.js +1 -1
- package/dist/lingui-extract.js +1 -1
- package/dist/lingui.js +1 -0
- package/dist/workers/missingWorker.d.ts +4 -0
- package/dist/workers/missingWorker.js +23 -0
- package/dist/workers/missingWorkerWrapper.prod.d.ts +3 -0
- package/dist/workers/missingWorkerWrapper.prod.js +2 -0
- package/package.json +8 -8
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const checkSpecificOptions = [
|
|
2
|
+
"clean",
|
|
3
|
+
"overwrite",
|
|
4
|
+
"missingBehavior",
|
|
5
|
+
];
|
|
6
|
+
export function finalizeCheckResult(name, findings, passMessage, failMessage) {
|
|
7
|
+
return {
|
|
8
|
+
name,
|
|
9
|
+
passed: findings.length === 0,
|
|
10
|
+
findings,
|
|
11
|
+
summary: findings.length === 0 ? passMessage : failMessage(findings.length),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -5,8 +5,9 @@ import { ProgramExit } from "../ProgramExit.js";
|
|
|
5
5
|
import { createCompiledCatalog } from "../compile.js";
|
|
6
6
|
import normalizePath from "normalize-path";
|
|
7
7
|
import nodepath from "path";
|
|
8
|
-
import { createCompilationErrorMessage } from "../messages.js";
|
|
8
|
+
import { createCompilationErrorMessage, getMissingBehaviorDescription, } from "../messages.js";
|
|
9
9
|
import { getTranslationsForCatalog } from "../catalog/getTranslationsForCatalog.js";
|
|
10
|
+
import { createMissingTranslationFinding } from "../catalog/translations.js";
|
|
10
11
|
export async function compileLocale(catalogs, locale, options, config, doMerge, logger) {
|
|
11
12
|
let mergedCatalogs = {};
|
|
12
13
|
for (const catalog of catalogs) {
|
|
@@ -20,16 +21,14 @@ export async function compileLocale(catalogs, locale, options, config, doMerge,
|
|
|
20
21
|
missingMessages.length > 0) {
|
|
21
22
|
logger.error(styleText("red", `Error: Failed to compile catalog for locale ${styleText("bold", locale)}!`));
|
|
22
23
|
if (options.verbose) {
|
|
23
|
-
logger.error(styleText("red",
|
|
24
|
+
logger.error(styleText("red", `Missing translations ${getMissingBehaviorDescription("resolved")}:`));
|
|
24
25
|
missingMessages.forEach((missing) => {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
: "";
|
|
28
|
-
logger.error(`${missing.id}${source}`);
|
|
26
|
+
const finding = createMissingTranslationFinding(catalog, locale, missing);
|
|
27
|
+
logger.error(`${finding.catalogPath}: ${finding.message}`);
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
else {
|
|
32
|
-
logger.error(styleText("red", `Missing ${missingMessages.length} translation(s)`));
|
|
31
|
+
logger.error(styleText("red", `Missing ${missingMessages.length} translation(s) ${getMissingBehaviorDescription("resolved")}`));
|
|
33
32
|
}
|
|
34
33
|
logger.error("");
|
|
35
34
|
throw new ProgramExit();
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function isBatchExtractor(ext: ExtractorType): ext is Experimental__BatchExtractorType;
|
|
3
|
-
export declare function isPerFileExtractor(ext: ExtractorType): ext is PerFileExtractorType;
|
|
4
|
-
export declare const getConfiguredExtractors: (linguiConfig: LinguiConfigNormalized) => ExtractorType[];
|
|
1
|
+
import { ExtractedMessage, LinguiConfigNormalized } from "@lingui/conf";
|
|
5
2
|
export default function extract(filename: string, onMessageExtracted: (msg: ExtractedMessage) => void, linguiConfig: LinguiConfigNormalized): Promise<boolean>;
|
|
@@ -9,17 +9,10 @@ function createDefaultExtractor(linguiConfig) {
|
|
|
9
9
|
}
|
|
10
10
|
return defaultExtractor;
|
|
11
11
|
}
|
|
12
|
-
export function isBatchExtractor(ext) {
|
|
13
|
-
return "extractFromFiles" in ext && typeof ext.extractFromFiles === "function";
|
|
14
|
-
}
|
|
15
|
-
export function isPerFileExtractor(ext) {
|
|
16
|
-
return "extract" in ext && typeof ext.extract === "function";
|
|
17
|
-
}
|
|
18
|
-
export const getConfiguredExtractors = (linguiConfig) => {
|
|
19
|
-
return linguiConfig.extractors ?? [createDefaultExtractor(linguiConfig)];
|
|
20
|
-
};
|
|
21
12
|
export default async function extract(filename, onMessageExtracted, linguiConfig) {
|
|
22
|
-
const extractorsToExtract =
|
|
13
|
+
const extractorsToExtract = linguiConfig.extractors ?? [
|
|
14
|
+
createDefaultExtractor(linguiConfig),
|
|
15
|
+
];
|
|
23
16
|
for (const ext of extractorsToExtract) {
|
|
24
17
|
if (!ext.match(filename))
|
|
25
18
|
continue;
|
|
@@ -5,6 +5,7 @@ export declare class FormatterWrapper {
|
|
|
5
5
|
constructor(f: CatalogFormatter, sourceLocale: string);
|
|
6
6
|
getCatalogExtension(): string;
|
|
7
7
|
getTemplateExtension(): string;
|
|
8
|
+
serialize(filename: string, catalog: CatalogType, locale?: string, existing?: string): Promise<string>;
|
|
8
9
|
write(filename: string, catalog: CatalogType, locale?: string): Promise<void>;
|
|
9
10
|
read(filename: string, locale: string | undefined): Promise<CatalogType | undefined>;
|
|
10
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile,
|
|
1
|
+
import { readFile, writeFile } from "../utils.js";
|
|
2
2
|
import { RethrownError } from "../rethrownError.js";
|
|
3
3
|
export class FormatterWrapper {
|
|
4
4
|
f;
|
|
@@ -13,14 +13,21 @@ export class FormatterWrapper {
|
|
|
13
13
|
getTemplateExtension() {
|
|
14
14
|
return this.f.templateExtension || this.f.catalogExtension;
|
|
15
15
|
}
|
|
16
|
-
async
|
|
17
|
-
const
|
|
16
|
+
async serialize(filename, catalog, locale, existing) {
|
|
17
|
+
const resolvedExisting = arguments.length >= 4 ? existing : await readFile(filename);
|
|
18
|
+
return await this.f.serialize(catalog, {
|
|
18
19
|
locale,
|
|
19
20
|
sourceLocale: this.sourceLocale,
|
|
20
|
-
existing:
|
|
21
|
+
existing: resolvedExisting,
|
|
21
22
|
filename,
|
|
22
23
|
});
|
|
23
|
-
|
|
24
|
+
}
|
|
25
|
+
async write(filename, catalog, locale) {
|
|
26
|
+
const existing = await readFile(filename);
|
|
27
|
+
const content = await this.serialize(filename, catalog, locale, existing);
|
|
28
|
+
if (content !== existing) {
|
|
29
|
+
await writeFile(filename, content);
|
|
30
|
+
}
|
|
24
31
|
}
|
|
25
32
|
async read(filename, locale) {
|
|
26
33
|
const content = await readFile(filename);
|
package/dist/api/index.d.ts
CHANGED
|
@@ -3,5 +3,7 @@ export { getCatalogForFile, getCatalogs } from "./catalog/getCatalogs.js";
|
|
|
3
3
|
export { createCompiledCatalog } from "./compile.js";
|
|
4
4
|
export { default as extractor, extractFromFileWithBabel, } from "./extractors/babel.js";
|
|
5
5
|
export { getCatalogDependentFiles } from "./catalog/getCatalogDependentFiles.js";
|
|
6
|
-
export { createMissingErrorMessage, createCompilationErrorMessage, } from "./messages.js";
|
|
6
|
+
export { createMissingErrorMessage, createCompilationErrorMessage, isFailOnMissingEnabled, getFailOnMissingBehavior, formatFailOnMissingOption, } from "./messages.js";
|
|
7
|
+
export type { FailOnMissingOption } from "./messages.js";
|
|
8
|
+
export type { MissingBehavior } from "./catalog/getTranslationsForCatalog.js";
|
|
7
9
|
export * from "./types.js";
|
package/dist/api/index.js
CHANGED
|
@@ -3,5 +3,5 @@ export { getCatalogForFile, getCatalogs } from "./catalog/getCatalogs.js";
|
|
|
3
3
|
export { createCompiledCatalog } from "./compile.js";
|
|
4
4
|
export { default as extractor, extractFromFileWithBabel, } from "./extractors/babel.js";
|
|
5
5
|
export { getCatalogDependentFiles } from "./catalog/getCatalogDependentFiles.js";
|
|
6
|
-
export { createMissingErrorMessage, createCompilationErrorMessage, } from "./messages.js";
|
|
6
|
+
export { createMissingErrorMessage, createCompilationErrorMessage, isFailOnMissingEnabled, getFailOnMissingBehavior, formatFailOnMissingOption, } from "./messages.js";
|
|
7
7
|
export * from "./types.js";
|
package/dist/api/messages.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import { TranslationMissingEvent } from "./catalog/getTranslationsForCatalog.js";
|
|
2
|
-
import { MessageCompilationError } from "./compile.js";
|
|
1
|
+
import { type MissingBehavior, type TranslationMissingEvent } from "./catalog/getTranslationsForCatalog.js";
|
|
2
|
+
import type { MessageCompilationError } from "./compile.js";
|
|
3
|
+
export declare function getMissingBehaviorDescription(missingBehavior: MissingBehavior): "before applying fallbackLocales" | "after applying fallbackLocales";
|
|
4
|
+
export type FailOnMissingOption = boolean | MissingBehavior;
|
|
5
|
+
export declare function isFailOnMissingEnabled(option: FailOnMissingOption | undefined): option is true | "resolved" | "catalog";
|
|
6
|
+
export declare function getFailOnMissingBehavior(option: FailOnMissingOption | undefined): MissingBehavior;
|
|
7
|
+
export declare function formatFailOnMissingOption(option: FailOnMissingOption | undefined): "true" | "\"resolved\"" | "\"catalog\"" | "false";
|
|
3
8
|
export declare function createMissingErrorMessage(locale: string, missingMessages: TranslationMissingEvent[], configurationMsg: string): string;
|
|
9
|
+
export declare function createMissingErrorMessage(locale: string, missingMessages: TranslationMissingEvent[], missingBehavior?: MissingBehavior): string;
|
|
4
10
|
export declare function createCompilationErrorMessage(locale: string, errors: MessageCompilationError[]): string;
|
package/dist/api/messages.js
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
|
+
import { isMissingBehavior, } from "./catalog/getTranslationsForCatalog.js";
|
|
1
2
|
import { styleText } from "node:util";
|
|
2
|
-
export function
|
|
3
|
+
export function getMissingBehaviorDescription(missingBehavior) {
|
|
4
|
+
return missingBehavior === "catalog"
|
|
5
|
+
? "before applying fallbackLocales"
|
|
6
|
+
: "after applying fallbackLocales";
|
|
7
|
+
}
|
|
8
|
+
export function isFailOnMissingEnabled(option) {
|
|
9
|
+
return option === true || option === "resolved" || option === "catalog";
|
|
10
|
+
}
|
|
11
|
+
export function getFailOnMissingBehavior(option) {
|
|
12
|
+
return option === "catalog" ? "catalog" : "resolved";
|
|
13
|
+
}
|
|
14
|
+
export function formatFailOnMissingOption(option) {
|
|
15
|
+
if (option === true)
|
|
16
|
+
return "true";
|
|
17
|
+
if (option === "resolved")
|
|
18
|
+
return '"resolved"';
|
|
19
|
+
if (option === "catalog")
|
|
20
|
+
return '"catalog"';
|
|
21
|
+
return "false";
|
|
22
|
+
}
|
|
23
|
+
export function createMissingErrorMessage(locale, missingMessages, missingBehaviorOrConfigurationMsg = "resolved") {
|
|
24
|
+
const missingBehavior = isMissingBehavior(missingBehaviorOrConfigurationMsg ?? "")
|
|
25
|
+
? missingBehaviorOrConfigurationMsg
|
|
26
|
+
: undefined;
|
|
27
|
+
const missingBehaviorDescription = missingBehavior
|
|
28
|
+
? ` ${getMissingBehaviorDescription(missingBehavior)}`
|
|
29
|
+
: "";
|
|
3
30
|
let message = `Failed to compile catalog for locale ${styleText("bold", locale)}!
|
|
4
31
|
|
|
5
|
-
Missing ${missingMessages.length} translation(s):
|
|
32
|
+
Missing ${missingMessages.length} translation(s)${missingBehaviorDescription}:
|
|
6
33
|
\n`;
|
|
7
34
|
missingMessages.forEach((missing) => {
|
|
8
35
|
const source = missing.source || missing.source === missing.id
|
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import * as os from "node:os";
|
|
2
|
+
function parseWorkers(workers) {
|
|
3
|
+
if (workers === undefined) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const parsedWorkers = Number(workers);
|
|
7
|
+
if (!Number.isFinite(parsedWorkers) || !Number.isInteger(parsedWorkers)) {
|
|
8
|
+
throw new Error("The `--workers` option must be an integer.");
|
|
9
|
+
}
|
|
10
|
+
return parsedWorkers;
|
|
11
|
+
}
|
|
2
12
|
export function resolveWorkersOptions(opts) {
|
|
3
13
|
const cores = os.availableParallelism();
|
|
4
|
-
|
|
14
|
+
const workers = parseWorkers(opts.workers);
|
|
15
|
+
if (workers !== undefined && workers <= 1) {
|
|
16
|
+
return { poolSize: 0 };
|
|
17
|
+
}
|
|
18
|
+
if (cores === 1) {
|
|
5
19
|
return { poolSize: 0 };
|
|
6
20
|
}
|
|
7
|
-
if (
|
|
21
|
+
if (workers === undefined) {
|
|
8
22
|
if (cores <= 2) {
|
|
9
23
|
return { poolSize: cores }; // on tiny machines, use all
|
|
10
24
|
}
|
|
11
25
|
// on big machines cap to 8, to avoid trashing
|
|
12
26
|
return { poolSize: Math.min(cores - 1, 8) };
|
|
13
27
|
}
|
|
14
|
-
return { poolSize:
|
|
28
|
+
return { poolSize: workers };
|
|
15
29
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runBounded<T, R>(items: readonly T[], concurrency: number, worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export async function runBounded(items, concurrency, worker) {
|
|
2
|
+
const results = new Array(items.length);
|
|
3
|
+
const workerCount = Math.min(Math.max(concurrency, 1), items.length);
|
|
4
|
+
let nextIndex = 0;
|
|
5
|
+
const pool = Array.from({ length: workerCount }, async () => {
|
|
6
|
+
while (nextIndex < items.length) {
|
|
7
|
+
const currentIndex = nextIndex++;
|
|
8
|
+
results[currentIndex] = await worker(items[currentIndex], currentIndex);
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
await Promise.all(pool);
|
|
12
|
+
return results;
|
|
13
|
+
}
|
package/dist/api/utils.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ export declare function makeInstall(packageName: string, dev?: boolean): string;
|
|
|
14
14
|
* Preserve absolute paths: /absolute/path => /absolute/path
|
|
15
15
|
*/
|
|
16
16
|
export declare function normalizeRelativePath(sourcePath: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Normalize a path relative to the project rootDir, for display purposes
|
|
19
|
+
* (e.g. finding.catalogPath).
|
|
20
|
+
*/
|
|
21
|
+
export declare function toRootRelativePath(rootDir: string, filePath: string): string;
|
|
17
22
|
/**
|
|
18
23
|
* Escape special regex characters used in file-based routing systems
|
|
19
24
|
*/
|
package/dist/api/utils.js
CHANGED
|
@@ -87,6 +87,13 @@ export function normalizeRelativePath(sourcePath) {
|
|
|
87
87
|
return (normalizePath(path.relative(process.cwd(), sourcePath), false) +
|
|
88
88
|
(isDir ? "/" : ""));
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Normalize a path relative to the project rootDir, for display purposes
|
|
92
|
+
* (e.g. finding.catalogPath).
|
|
93
|
+
*/
|
|
94
|
+
export function toRootRelativePath(rootDir, filePath) {
|
|
95
|
+
return normalizePath(path.relative(rootDir, filePath));
|
|
96
|
+
}
|
|
90
97
|
/**
|
|
91
98
|
* Escape special regex characters used in file-based routing systems
|
|
92
99
|
*/
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { WorkerPool } from "./typedPool.js";
|
|
2
2
|
import type { ExtractWorkerFunction } from "../workers/extractWorker.js";
|
|
3
|
+
import type { MissingWorkerFunction } from "../workers/missingWorker.js";
|
|
3
4
|
export type ExtractWorkerPool = WorkerPool<ExtractWorkerFunction>;
|
|
5
|
+
export type MissingWorkerPool = WorkerPool<MissingWorkerFunction>;
|
package/dist/api/workerPools.js
CHANGED
|
@@ -5,3 +5,5 @@ export const createExtractWorkerPool = (opts) => createWorkerPool("../workers/ex
|
|
|
5
5
|
export const createExtractExperimentalWorkerPool = (opts) => createWorkerPool("../extract-experimental/workers/extractWorkerWrapper", import.meta.url, opts.poolSize);
|
|
6
6
|
/** @internal */
|
|
7
7
|
export const createCompileWorkerPool = (opts) => createWorkerPool("../workers/compileWorkerWrapper", import.meta.url, opts.poolSize);
|
|
8
|
+
/** @internal */
|
|
9
|
+
export const createMissingWorkerPool = (opts) => createWorkerPool("../workers/missingWorkerWrapper", import.meta.url, opts.poolSize);
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { defineConfig } from "@lingui/conf";
|
|
1
|
+
export { defineConfig, type LinguiConfig } from "@lingui/conf";
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { LinguiConfigNormalized } from "@lingui/conf";
|
|
3
|
+
import { CheckName, CheckRunOptions, CheckResult } from "./api/check/types.js";
|
|
4
|
+
export declare function renderCheckResult(result: CheckResult, verbose: boolean): string[];
|
|
5
|
+
export declare function runCheck(config: LinguiConfigNormalized, check: CheckName, options: CheckRunOptions): Promise<CheckResult>;
|
|
6
|
+
export declare function createProgram(): Command;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import ms from "ms";
|
|
4
|
+
import { getConfig } from "@lingui/conf";
|
|
5
|
+
import { helpRun } from "./api/help.js";
|
|
6
|
+
import { getCatalogs } from "./api/index.js";
|
|
7
|
+
import { getCheck, getRegisteredChecks, validateSupportedOptions, } from "./api/check/index.js";
|
|
8
|
+
import { resolveWorkersOptions } from "./api/resolveWorkersOptions.js";
|
|
9
|
+
import { isMissingBehavior } from "./api/catalog/getTranslationsForCatalog.js";
|
|
10
|
+
export function renderCheckResult(result, verbose) {
|
|
11
|
+
const status = result.passed
|
|
12
|
+
? styleText("green", "PASS")
|
|
13
|
+
: styleText("red", "FAIL");
|
|
14
|
+
const lines = [`${status} ${result.name}: ${result.summary}`];
|
|
15
|
+
if (verbose) {
|
|
16
|
+
lines.push(...result.findings.map((finding) => `${finding.catalogPath}: ${finding.message}`));
|
|
17
|
+
}
|
|
18
|
+
return lines;
|
|
19
|
+
}
|
|
20
|
+
function validateLocales(config, locales) {
|
|
21
|
+
if (!locales?.length) {
|
|
22
|
+
return config.locales;
|
|
23
|
+
}
|
|
24
|
+
const missingLocale = locales.find((locale) => !config.locales.includes(locale));
|
|
25
|
+
if (missingLocale) {
|
|
26
|
+
throw new Error(`Locale ${styleText("bold", missingLocale)} does not exist.`);
|
|
27
|
+
}
|
|
28
|
+
return locales;
|
|
29
|
+
}
|
|
30
|
+
export async function runCheck(config, check, options) {
|
|
31
|
+
const checkDefinition = getCheck(check);
|
|
32
|
+
validateSupportedOptions(checkDefinition, options);
|
|
33
|
+
const locales = validateLocales(config, options.locale);
|
|
34
|
+
const catalogs = await getCatalogs(config);
|
|
35
|
+
return await checkDefinition.run({
|
|
36
|
+
config,
|
|
37
|
+
catalogs,
|
|
38
|
+
locales,
|
|
39
|
+
workersOptions: options.workersOptions,
|
|
40
|
+
clean: options.clean ?? false,
|
|
41
|
+
overwrite: options.overwrite ?? false,
|
|
42
|
+
missingBehavior: options.missingBehavior ?? "resolved",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function parseLocales(value) {
|
|
46
|
+
return value
|
|
47
|
+
.split(",")
|
|
48
|
+
.map((locale) => locale.trim())
|
|
49
|
+
.filter(Boolean);
|
|
50
|
+
}
|
|
51
|
+
function addCommonOptions(command) {
|
|
52
|
+
return command
|
|
53
|
+
.option("--config <path>", "Path to the config file")
|
|
54
|
+
.option("--locale <locale, [...]>", "Only check the specified locales", parseLocales)
|
|
55
|
+
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8; on 1-2 core machines, all cores). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
56
|
+
.option("--verbose", "Verbose output");
|
|
57
|
+
}
|
|
58
|
+
function parseMissingBehavior(value) {
|
|
59
|
+
if (isMissingBehavior(value)) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
throw new Error("Option `--mode` must be either `resolved` or `catalog`.");
|
|
63
|
+
}
|
|
64
|
+
function renderHelpExamples(examples) {
|
|
65
|
+
if (!examples.length) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
console.log("\n Examples:\n");
|
|
69
|
+
examples.forEach((example, index) => {
|
|
70
|
+
console.log(` # ${example.description}`);
|
|
71
|
+
console.log(` $ ${helpRun(example.command)}`);
|
|
72
|
+
if (index < examples.length - 1) {
|
|
73
|
+
console.log("");
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async function runCliCommand(check, options) {
|
|
78
|
+
const startTime = Date.now();
|
|
79
|
+
const config = getConfig({ configPath: options.config });
|
|
80
|
+
const verbose = options.verbose ?? false;
|
|
81
|
+
console.log("Checking message catalogs…");
|
|
82
|
+
const result = await runCheck(config, check, {
|
|
83
|
+
locale: options.locale,
|
|
84
|
+
workersOptions: resolveWorkersOptions(options),
|
|
85
|
+
clean: options.clean,
|
|
86
|
+
overwrite: options.overwrite,
|
|
87
|
+
missingBehavior: options.mode,
|
|
88
|
+
});
|
|
89
|
+
const output = result.passed ? console.log : console.error;
|
|
90
|
+
renderCheckResult(result, verbose).forEach((line) => {
|
|
91
|
+
output(line);
|
|
92
|
+
});
|
|
93
|
+
console.log(`Done in ${ms(Date.now() - startTime)}`);
|
|
94
|
+
return result.passed;
|
|
95
|
+
}
|
|
96
|
+
function registerCheckCommand(checkProgram, check) {
|
|
97
|
+
const command = addCommonOptions(checkProgram.command(check.name).description(check.description));
|
|
98
|
+
check.cli.options.forEach((option) => {
|
|
99
|
+
if (option.name === "mode") {
|
|
100
|
+
command.option(`--${option.name} <mode>`, option.description, parseMissingBehavior);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
command.option(`--${option.name}`, option.description);
|
|
104
|
+
});
|
|
105
|
+
command
|
|
106
|
+
.on("--help", function () {
|
|
107
|
+
renderHelpExamples(check.cli.examples);
|
|
108
|
+
})
|
|
109
|
+
.action(async (options) => {
|
|
110
|
+
if (!(await runCliCommand(check.name, options))) {
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
export function createProgram() {
|
|
116
|
+
const checkProgram = new Command()
|
|
117
|
+
.name("lingui check")
|
|
118
|
+
.description("Check message catalogs.")
|
|
119
|
+
.action(() => {
|
|
120
|
+
checkProgram.help({ error: true });
|
|
121
|
+
})
|
|
122
|
+
.on("--help", function () {
|
|
123
|
+
renderHelpExamples(getRegisteredChecks().flatMap((check) => check.cli.examples));
|
|
124
|
+
});
|
|
125
|
+
getRegisteredChecks().forEach((check) => {
|
|
126
|
+
registerCheckCommand(checkProgram, check);
|
|
127
|
+
});
|
|
128
|
+
return checkProgram;
|
|
129
|
+
}
|
|
130
|
+
if (import.meta.main) {
|
|
131
|
+
createProgram()
|
|
132
|
+
.parseAsync(process.argv)
|
|
133
|
+
.catch((error) => {
|
|
134
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
137
|
+
}
|
package/dist/lingui-compile.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createCompileWorkerPool } from "./api/workerPools.js";
|
|
|
9
9
|
import { resolveWorkersOptions, } from "./api/resolveWorkersOptions.js";
|
|
10
10
|
import ms from "ms";
|
|
11
11
|
import { getPathsForCompileWatcher } from "./api/getPathsForCompileWatcher.js";
|
|
12
|
+
import { ProgramExit } from "./api/ProgramExit.js";
|
|
12
13
|
export async function command(config, options) {
|
|
13
14
|
const startTime = Date.now();
|
|
14
15
|
// Check config.compile.merge if catalogs for current locale are to be merged into a single compiled file
|
|
@@ -23,7 +24,7 @@ export async function command(config, options) {
|
|
|
23
24
|
await compileLocale(catalogs, locale, options, config, doMerge, console);
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
26
|
-
if (err
|
|
27
|
+
if (err instanceof ProgramExit) {
|
|
27
28
|
errored = true;
|
|
28
29
|
}
|
|
29
30
|
else {
|
|
@@ -68,10 +69,10 @@ if (import.meta.main) {
|
|
|
68
69
|
program
|
|
69
70
|
.description("Compile message catalogs to compiled bundle.")
|
|
70
71
|
.option("--config <path>", "Path to the config file")
|
|
71
|
-
.option("--strict", "
|
|
72
|
+
.option("--strict", "Fail if translations are missing after applying fallbackLocales, or if compilation errors occur")
|
|
72
73
|
.option("--verbose", "Verbose output")
|
|
73
74
|
.option("--typescript", "Create Typescript definition for compiled bundle")
|
|
74
|
-
.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")
|
|
75
|
+
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8; on 1-2 core machines, all cores). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
75
76
|
.option("--namespace <namespace>", "Specify namespace for compiled bundle. Ex: cjs(default) -> module.exports, es -> export, window.test -> window.test")
|
|
76
77
|
.option("--watch", "Enables Watch Mode")
|
|
77
78
|
.option("--debounce <delay>", "Debounces compilation for given amount of milliseconds")
|
|
@@ -81,9 +82,8 @@ if (import.meta.main) {
|
|
|
81
82
|
console.log(" # Compile translations and use defaults or message IDs for missing translations");
|
|
82
83
|
console.log(` $ ${helpRun("compile")}`);
|
|
83
84
|
console.log("");
|
|
84
|
-
console.log(" # Compile translations but fail when
|
|
85
|
-
console.log(" #
|
|
86
|
-
console.log(" # default messages or message IDs)");
|
|
85
|
+
console.log(" # Compile translations but fail when resolved output");
|
|
86
|
+
console.log(" # still has missing translations or compilation errors");
|
|
87
87
|
console.log(` $ ${helpRun("compile --strict")}`);
|
|
88
88
|
})
|
|
89
89
|
.parse(process.argv);
|
|
@@ -183,7 +183,7 @@ if (import.meta.main) {
|
|
|
183
183
|
.option("--clean", "Remove obsolete translations")
|
|
184
184
|
.option("--locale <locale, [...]>", "Only extract the specified locales")
|
|
185
185
|
.option("--verbose", "Verbose output")
|
|
186
|
-
.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")
|
|
186
|
+
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8; on 1-2 core machines, all cores). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
187
187
|
.parse(process.argv);
|
|
188
188
|
const options = program.opts();
|
|
189
189
|
const config = getConfig({
|
|
@@ -45,7 +45,7 @@ if (import.meta.main) {
|
|
|
45
45
|
program
|
|
46
46
|
.option("--config <path>", "Path to the config file")
|
|
47
47
|
.option("--verbose", "Verbose output")
|
|
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")
|
|
48
|
+
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8; on 1-2 core machines, all cores). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
49
49
|
.parse(process.argv);
|
|
50
50
|
const options = program.opts();
|
|
51
51
|
const config = getConfig({
|
package/dist/lingui-extract.js
CHANGED
|
@@ -97,7 +97,7 @@ if (import.meta.main) {
|
|
|
97
97
|
.map((s) => s.trim())
|
|
98
98
|
.filter(Boolean);
|
|
99
99
|
})
|
|
100
|
-
.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")
|
|
100
|
+
.option("--workers <n>", "Number of worker threads to use (default: CPU count - 1, capped at 8; on 1-2 core machines, all cores). Pass `--workers 1` to disable worker threads and run everything in a single process")
|
|
101
101
|
.option("--overwrite", "Overwrite translations for source locale")
|
|
102
102
|
.option("--clean", "Remove obsolete translations")
|
|
103
103
|
.option("--debounce <delay>", "Debounces extraction for given amount of milliseconds")
|
package/dist/lingui.js
CHANGED
|
@@ -8,5 +8,6 @@ program
|
|
|
8
8
|
.command("extract [files...]", "Extracts messages from source files")
|
|
9
9
|
.command("extract-experimental", "Extracts messages from source files traversing dependency tree")
|
|
10
10
|
.command("extract-template", "Extracts messages from source files to a .pot template")
|
|
11
|
+
.command("check", "Checks message catalogs")
|
|
11
12
|
.command("compile", "Compile message catalogs")
|
|
12
13
|
.parse(process.argv);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MissingTranslationFinding } from "../api/catalog/translations.js";
|
|
2
|
+
import type { MissingBehavior } from "../api/catalog/getTranslationsForCatalog.js";
|
|
3
|
+
export type MissingWorkerFunction = typeof missingWorker;
|
|
4
|
+
export declare const missingWorker: (catalogPath: string, locale: string, missingBehavior: MissingBehavior, linguiConfigPath: string) => Promise<MissingTranslationFinding[]>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getConfig } from "@lingui/conf";
|
|
2
|
+
import { getCatalogs } from "../api/catalog/getCatalogs.js";
|
|
3
|
+
import { getMissingTranslationFindings, } from "../api/catalog/translations.js";
|
|
4
|
+
let linguiConfig;
|
|
5
|
+
let catalogs;
|
|
6
|
+
export const missingWorker = async (catalogPath, locale, missingBehavior, linguiConfigPath) => {
|
|
7
|
+
if (!linguiConfig) {
|
|
8
|
+
// initialize config once per worker, speed up workers follow execution
|
|
9
|
+
linguiConfig = getConfig({
|
|
10
|
+
configPath: linguiConfigPath,
|
|
11
|
+
skipValidation: true,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
if (!catalogs) {
|
|
15
|
+
// catalogs depend only on the config, so initialize them once per worker
|
|
16
|
+
catalogs = await getCatalogs(linguiConfig);
|
|
17
|
+
}
|
|
18
|
+
const catalog = catalogs.find((catalog) => catalog.path === catalogPath);
|
|
19
|
+
if (!catalog) {
|
|
20
|
+
throw new Error(`Unable to find catalog at path ${catalogPath}.`);
|
|
21
|
+
}
|
|
22
|
+
return getMissingTranslationFindings(catalog, locale, missingBehavior);
|
|
23
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingui/cli",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.8.0",
|
|
4
4
|
"description": "Lingui CLI: extracts i18n messages from source code into catalogs and compiles the translated catalogs for the runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"@babel/generator": "^7.28.5",
|
|
55
55
|
"@babel/parser": "^7.22.0",
|
|
56
56
|
"@babel/types": "^7.21.2",
|
|
57
|
-
"@lingui/babel-plugin-extract-messages": "6.
|
|
58
|
-
"@lingui/babel-plugin-lingui-macro": "6.
|
|
59
|
-
"@lingui/conf": "6.
|
|
60
|
-
"@lingui/core": "6.
|
|
61
|
-
"@lingui/format-po": "6.
|
|
62
|
-
"@lingui/message-utils": "6.
|
|
57
|
+
"@lingui/babel-plugin-extract-messages": "6.8.0",
|
|
58
|
+
"@lingui/babel-plugin-lingui-macro": "6.8.0",
|
|
59
|
+
"@lingui/conf": "6.8.0",
|
|
60
|
+
"@lingui/core": "6.8.0",
|
|
61
|
+
"@lingui/format-po": "6.8.0",
|
|
62
|
+
"@lingui/message-utils": "6.8.0",
|
|
63
63
|
"chokidar": "5.0.0",
|
|
64
64
|
"cli-table3": "^0.6.5",
|
|
65
65
|
"commander": "^14.0.2",
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"rolldown": "^1.1.1",
|
|
98
98
|
"vitest": "catalog:"
|
|
99
99
|
},
|
|
100
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "8c0f1ba378076cc49b320cccd2e06c60afe94963"
|
|
101
101
|
}
|