@lingual/i18n-check 0.8.0 → 0.8.2
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/bin/index.js +22 -45
- package/dist/bin/index.test.js +570 -451
- package/dist/errorReporters.d.ts +5 -7
- package/dist/errorReporters.js +59 -73
- package/dist/errorReporters.test.d.ts +1 -0
- package/dist/errorReporters.test.js +165 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +21 -14
- package/dist/types.d.ts +5 -0
- package/dist/utils/findInvalidTranslations.d.ts +3 -6
- package/dist/utils/findInvalidTranslations.js +3 -3
- package/dist/utils/findInvalidi18nTranslations.d.ts +3 -3
- package/dist/utils/findInvalidi18nTranslations.js +1 -1
- package/dist/utils/findMissingKeys.d.ts +1 -1
- package/dist/utils/findMissingKeys.js +1 -1
- package/dist/utils/flattenTranslations.js +1 -1
- package/dist/utils/nextIntlSrcParser.test.js +50 -50
- package/package.json +1 -1
package/dist/errorReporters.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CheckResult, InvalidTranslationsResult } from "./types";
|
|
1
2
|
export type StandardReporter = {
|
|
2
3
|
file: string;
|
|
3
4
|
key: string;
|
|
@@ -6,10 +7,7 @@ export type StandardReporter = {
|
|
|
6
7
|
export declare const CheckOptions: string[];
|
|
7
8
|
export type Context = (typeof CheckOptions)[number];
|
|
8
9
|
export declare const contextMapping: Record<Context, string>;
|
|
9
|
-
export declare
|
|
10
|
-
export declare
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}[]) => string;
|
|
14
|
-
export declare const createTable: (input: unknown[]) => string;
|
|
15
|
-
export declare const createVerticalTable: (input: unknown[]) => string;
|
|
10
|
+
export declare function formatSummaryTable<T>(result: Record<string, T[]>): string;
|
|
11
|
+
export declare function formatTable(rowGroups: string[][][], lineSep?: string): string;
|
|
12
|
+
export declare function formatCheckResultTable(result: CheckResult): string;
|
|
13
|
+
export declare function formatInvalidTranslationsResultTable(result: InvalidTranslationsResult): string;
|
package/dist/errorReporters.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
exports.contextMapping = exports.CheckOptions = void 0;
|
|
4
|
+
exports.formatSummaryTable = formatSummaryTable;
|
|
5
|
+
exports.formatTable = formatTable;
|
|
6
|
+
exports.formatCheckResultTable = formatCheckResultTable;
|
|
7
|
+
exports.formatInvalidTranslationsResultTable = formatInvalidTranslationsResultTable;
|
|
6
8
|
exports.CheckOptions = [
|
|
7
9
|
"invalidKeys",
|
|
8
10
|
"missingKeys",
|
|
@@ -15,78 +17,62 @@ exports.contextMapping = {
|
|
|
15
17
|
unused: "unused",
|
|
16
18
|
undefined: "undefined",
|
|
17
19
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, []);
|
|
26
|
-
return (0, exports.createVerticalTable)(data);
|
|
20
|
+
function formatSummaryTable(result) {
|
|
21
|
+
return formatTable(getSummaryRows(result));
|
|
22
|
+
}
|
|
23
|
+
const getSummaryRows = (checkResult) => {
|
|
24
|
+
const rows = [];
|
|
25
|
+
for (const [file, keys] of Object.entries(checkResult)) {
|
|
26
|
+
rows.push([truncate(file), String(keys.length)]);
|
|
27
27
|
}
|
|
28
|
-
return
|
|
28
|
+
return [[["file", "total"]], rows];
|
|
29
29
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
cb(null, chunk);
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
const logger = new console_1.Console({ stdout: ts });
|
|
43
|
-
logger.table(input);
|
|
44
|
-
const table = (ts.read() || "").toString();
|
|
45
|
-
// https://stackoverflow.com/a/69874540
|
|
46
|
-
let output = "";
|
|
47
|
-
const lines = table.split(/[\r\n]+/);
|
|
48
|
-
for (let line of lines) {
|
|
49
|
-
output += `${line
|
|
50
|
-
.replace(/[^┬]*┬/, "┌")
|
|
51
|
-
.replace(/^├─*┼/, "├")
|
|
52
|
-
.replace(/│[^│]*/, "")
|
|
53
|
-
.replace(/^└─*┴/, "└")
|
|
54
|
-
.replace(/'/g, " ")}\n`;
|
|
55
|
-
}
|
|
56
|
-
return output.replace(/\n\n$/, "");
|
|
57
|
-
};
|
|
58
|
-
exports.createTable = createTable;
|
|
59
|
-
const createVerticalTable = (input) => {
|
|
60
|
-
// https://stackoverflow.com/a/67859384
|
|
61
|
-
const ts = new stream_1.Transform({
|
|
62
|
-
transform(chunk, enc, cb) {
|
|
63
|
-
cb(null, chunk);
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
const logger = new console_1.Console({ stdout: ts });
|
|
67
|
-
logger.table(input);
|
|
68
|
-
const table = (ts.read() || "").toString();
|
|
69
|
-
// https://stackoverflow.com/a/69874540
|
|
70
|
-
let output = "";
|
|
71
|
-
let firstLine = "";
|
|
72
|
-
let index = 0;
|
|
73
|
-
const lines = table.split(/[\r\n]+/);
|
|
74
|
-
for (let line of lines) {
|
|
75
|
-
const transformedLine = `${line
|
|
76
|
-
.replace(/[^┬]*┬/, "┌")
|
|
77
|
-
.replace(/^├─*┼/, "├")
|
|
78
|
-
.replace(/│[^│]*/, "")
|
|
79
|
-
.replace(/^└─*┴/, "└")
|
|
80
|
-
.replace(/'/g, " ")}\n`;
|
|
81
|
-
output += transformedLine;
|
|
82
|
-
if (index === 2) {
|
|
83
|
-
firstLine = transformedLine;
|
|
30
|
+
function formatTable(rowGroups, lineSep = "\n") {
|
|
31
|
+
// +2 for whitespace padding left and right
|
|
32
|
+
const padding = 2;
|
|
33
|
+
const colWidths = [];
|
|
34
|
+
for (const rows of rowGroups) {
|
|
35
|
+
for (const row of rows) {
|
|
36
|
+
for (let index = 0; index < row.length; ++index) {
|
|
37
|
+
colWidths[index] = Math.max(colWidths[index] ?? 0, row[index].length + padding);
|
|
38
|
+
}
|
|
84
39
|
}
|
|
85
|
-
|
|
86
|
-
|
|
40
|
+
}
|
|
41
|
+
const lines = [];
|
|
42
|
+
lines.push(formatSeparatorRow(colWidths, "┌┬┐"));
|
|
43
|
+
for (const rows of rowGroups) {
|
|
44
|
+
for (const row of rows) {
|
|
45
|
+
lines.push(formatRow(row, colWidths));
|
|
87
46
|
}
|
|
88
|
-
|
|
47
|
+
lines.push(formatSeparatorRow(colWidths, "├┼┤"));
|
|
89
48
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
49
|
+
lines[lines.length - 1] = formatSeparatorRow(colWidths, "└┴┘");
|
|
50
|
+
return lines.join(lineSep);
|
|
51
|
+
}
|
|
52
|
+
function formatSeparatorRow(widths, [left, middle, right]) {
|
|
53
|
+
return (left + widths.map((width) => "".padEnd(width, "─")).join(middle) + right);
|
|
54
|
+
}
|
|
55
|
+
function formatRow(values, widths) {
|
|
56
|
+
return (`│` +
|
|
57
|
+
values
|
|
58
|
+
.map((val, index) => ` ${val} `.padEnd(widths[index], " "))
|
|
59
|
+
.join("│") +
|
|
60
|
+
`│`);
|
|
61
|
+
}
|
|
62
|
+
const truncate = (chars, len = 80) => chars.length > 80 ? `${chars.substring(0, len)}...` : chars;
|
|
63
|
+
function formatCheckResultTable(result) {
|
|
64
|
+
return formatTable([
|
|
65
|
+
[["file", "key"]],
|
|
66
|
+
Object.entries(result).flatMap(([file, keys]) => keys.map((key) => [truncate(file), truncate(key)])),
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
function formatInvalidTranslationsResultTable(result) {
|
|
70
|
+
return formatTable([
|
|
71
|
+
[["info", "result"]],
|
|
72
|
+
...Object.entries(result).flatMap(([file, errors]) => errors.map(({ key, msg }) => [
|
|
73
|
+
["file", truncate(file)],
|
|
74
|
+
["key", truncate(key)],
|
|
75
|
+
["msg", truncate(msg, 120)],
|
|
76
|
+
])),
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const errorReporters_1 = require("./errorReporters");
|
|
4
|
+
describe("formatTable", () => {
|
|
5
|
+
test("single col and row", () => {
|
|
6
|
+
expect((0, errorReporters_1.formatTable)([[["lorem ipsum"]]])).toEqual(`
|
|
7
|
+
┌─────────────┐
|
|
8
|
+
│ lorem ipsum │
|
|
9
|
+
└─────────────┘
|
|
10
|
+
`.trim());
|
|
11
|
+
});
|
|
12
|
+
test("single col and two rows", () => {
|
|
13
|
+
expect((0, errorReporters_1.formatTable)([[["lorem ipsum"], ["foo bar"]]])).toEqual(`
|
|
14
|
+
┌─────────────┐
|
|
15
|
+
│ lorem ipsum │
|
|
16
|
+
│ foo bar │
|
|
17
|
+
└─────────────┘
|
|
18
|
+
`.trim());
|
|
19
|
+
});
|
|
20
|
+
test("with two columns and two row groups", () => {
|
|
21
|
+
expect((0, errorReporters_1.formatTable)([
|
|
22
|
+
[["col1", "col2"]],
|
|
23
|
+
[
|
|
24
|
+
["lorem ipsum dolor", "foobar"],
|
|
25
|
+
["baz", "more text"],
|
|
26
|
+
],
|
|
27
|
+
])).toEqual(`
|
|
28
|
+
┌───────────────────┬───────────┐
|
|
29
|
+
│ col1 │ col2 │
|
|
30
|
+
├───────────────────┼───────────┤
|
|
31
|
+
│ lorem ipsum dolor │ foobar │
|
|
32
|
+
│ baz │ more text │
|
|
33
|
+
└───────────────────┴───────────┘
|
|
34
|
+
`.trim());
|
|
35
|
+
});
|
|
36
|
+
test("with two columns and three row groups", () => {
|
|
37
|
+
expect((0, errorReporters_1.formatTable)([
|
|
38
|
+
[["one", "two"]],
|
|
39
|
+
[
|
|
40
|
+
["lorem ipsum dolor", "foobar"],
|
|
41
|
+
["baz", "more text"],
|
|
42
|
+
],
|
|
43
|
+
[["hello world", "here is more text for testing"]],
|
|
44
|
+
])).toEqual(`
|
|
45
|
+
┌───────────────────┬───────────────────────────────┐
|
|
46
|
+
│ one │ two │
|
|
47
|
+
├───────────────────┼───────────────────────────────┤
|
|
48
|
+
│ lorem ipsum dolor │ foobar │
|
|
49
|
+
│ baz │ more text │
|
|
50
|
+
├───────────────────┼───────────────────────────────┤
|
|
51
|
+
│ hello world │ here is more text for testing │
|
|
52
|
+
└───────────────────┴───────────────────────────────┘
|
|
53
|
+
`.trim());
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe("formatCheckResultTable", () => {
|
|
57
|
+
test("with one file and two keys", () => {
|
|
58
|
+
expect((0, errorReporters_1.formatCheckResultTable)({
|
|
59
|
+
"some/file.json": ["key.one", "key.two"],
|
|
60
|
+
})).toEqual(`
|
|
61
|
+
┌────────────────┬─────────┐
|
|
62
|
+
│ file │ key │
|
|
63
|
+
├────────────────┼─────────┤
|
|
64
|
+
│ some/file.json │ key.one │
|
|
65
|
+
│ some/file.json │ key.two │
|
|
66
|
+
└────────────────┴─────────┘
|
|
67
|
+
`.trim());
|
|
68
|
+
});
|
|
69
|
+
test("with two files and three keys", () => {
|
|
70
|
+
expect((0, errorReporters_1.formatCheckResultTable)({
|
|
71
|
+
"some/de.json": ["key.one", "key.two"],
|
|
72
|
+
"some/en.json": ["key.three"],
|
|
73
|
+
})).toEqual(`
|
|
74
|
+
┌──────────────┬───────────┐
|
|
75
|
+
│ file │ key │
|
|
76
|
+
├──────────────┼───────────┤
|
|
77
|
+
│ some/de.json │ key.one │
|
|
78
|
+
│ some/de.json │ key.two │
|
|
79
|
+
│ some/en.json │ key.three │
|
|
80
|
+
└──────────────┴───────────┘
|
|
81
|
+
`.trim());
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("formatInvalidTranslationsResultTable", () => {
|
|
85
|
+
test("with one file and one key", () => {
|
|
86
|
+
expect((0, errorReporters_1.formatInvalidTranslationsResultTable)({
|
|
87
|
+
"some/en.json": [{ key: "key.one", msg: "key one error msg" }],
|
|
88
|
+
})).toEqual(`
|
|
89
|
+
┌──────┬───────────────────┐
|
|
90
|
+
│ info │ result │
|
|
91
|
+
├──────┼───────────────────┤
|
|
92
|
+
│ file │ some/en.json │
|
|
93
|
+
│ key │ key.one │
|
|
94
|
+
│ msg │ key one error msg │
|
|
95
|
+
└──────┴───────────────────┘
|
|
96
|
+
`.trim());
|
|
97
|
+
});
|
|
98
|
+
test("with two files and three keys", () => {
|
|
99
|
+
expect((0, errorReporters_1.formatInvalidTranslationsResultTable)({
|
|
100
|
+
"some/en-US.json": [
|
|
101
|
+
{ key: "key.one", msg: "key one error msg" },
|
|
102
|
+
{ key: "key.two", msg: "another msg" },
|
|
103
|
+
],
|
|
104
|
+
"some/de.json": [{ key: "key.three", msg: "key three msg" }],
|
|
105
|
+
})).toEqual(`
|
|
106
|
+
┌──────┬───────────────────┐
|
|
107
|
+
│ info │ result │
|
|
108
|
+
├──────┼───────────────────┤
|
|
109
|
+
│ file │ some/en-US.json │
|
|
110
|
+
│ key │ key.one │
|
|
111
|
+
│ msg │ key one error msg │
|
|
112
|
+
├──────┼───────────────────┤
|
|
113
|
+
│ file │ some/en-US.json │
|
|
114
|
+
│ key │ key.two │
|
|
115
|
+
│ msg │ another msg │
|
|
116
|
+
├──────┼───────────────────┤
|
|
117
|
+
│ file │ some/de.json │
|
|
118
|
+
│ key │ key.three │
|
|
119
|
+
│ msg │ key three msg │
|
|
120
|
+
└──────┴───────────────────┘
|
|
121
|
+
`.trim());
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe("formatSummaryTable", () => {
|
|
125
|
+
test("with CheckResult with single file and key", () => {
|
|
126
|
+
expect((0, errorReporters_1.formatSummaryTable)({
|
|
127
|
+
"some/file.json": ["key.one"],
|
|
128
|
+
})).toEqual(`
|
|
129
|
+
┌────────────────┬───────┐
|
|
130
|
+
│ file │ total │
|
|
131
|
+
├────────────────┼───────┤
|
|
132
|
+
│ some/file.json │ 1 │
|
|
133
|
+
└────────────────┴───────┘
|
|
134
|
+
`.trim());
|
|
135
|
+
});
|
|
136
|
+
test("with CheckResult with two files and three keys", () => {
|
|
137
|
+
expect((0, errorReporters_1.formatSummaryTable)({
|
|
138
|
+
"some/de.json": ["key.one", "key.two"],
|
|
139
|
+
"some/en.json": ["key.three"],
|
|
140
|
+
})).toEqual(`
|
|
141
|
+
┌──────────────┬───────┐
|
|
142
|
+
│ file │ total │
|
|
143
|
+
├──────────────┼───────┤
|
|
144
|
+
│ some/de.json │ 2 │
|
|
145
|
+
│ some/en.json │ 1 │
|
|
146
|
+
└──────────────┴───────┘
|
|
147
|
+
`.trim());
|
|
148
|
+
});
|
|
149
|
+
test("with InvalidTranslationsResult with two files and three keys", () => {
|
|
150
|
+
expect((0, errorReporters_1.formatSummaryTable)({
|
|
151
|
+
"some/en-US.json": [
|
|
152
|
+
{ key: "key.one", msg: "key one error msg" },
|
|
153
|
+
{ key: "key.two", msg: "another msg" },
|
|
154
|
+
],
|
|
155
|
+
"some/de.json": [{ key: "key.three", msg: "key three msg" }],
|
|
156
|
+
})).toEqual(`
|
|
157
|
+
┌─────────────────┬───────┐
|
|
158
|
+
│ file │ total │
|
|
159
|
+
├─────────────────┼───────┤
|
|
160
|
+
│ some/en-US.json │ 2 │
|
|
161
|
+
│ some/de.json │ 1 │
|
|
162
|
+
└─────────────────┴───────┘
|
|
163
|
+
`.trim());
|
|
164
|
+
});
|
|
165
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { CheckResult, Translation, TranslationFile } from "./types";
|
|
1
|
+
import { CheckResult, InvalidTranslationsResult, Translation, TranslationFile } from "./types";
|
|
2
2
|
import { Context } from "./errorReporters";
|
|
3
3
|
export type Options = {
|
|
4
4
|
format?: "icu" | "i18next" | "react-intl" | "next-intl";
|
|
5
5
|
checks?: Context[];
|
|
6
6
|
};
|
|
7
|
-
export declare const checkInvalidTranslations: (source: Translation, targets: Record<string, Translation>, options?: Options) =>
|
|
7
|
+
export declare const checkInvalidTranslations: (source: Translation, targets: Record<string, Translation>, options?: Options) => InvalidTranslationsResult;
|
|
8
8
|
export declare const checkMissingTranslations: (source: Translation, targets: Record<string, Translation>) => CheckResult;
|
|
9
9
|
export declare const checkTranslations: (source: TranslationFile[], targets: TranslationFile[], options?: Options) => {
|
|
10
10
|
missingKeys: CheckResult | undefined;
|
|
11
|
-
invalidKeys:
|
|
11
|
+
invalidKeys: InvalidTranslationsResult | undefined;
|
|
12
12
|
};
|
|
13
|
-
export declare const checkUnusedKeys: (translationFiles: TranslationFile[], filesToParse: string[], options?: Options, componentFunctions?:
|
|
14
|
-
export declare const checkUndefinedKeys: (source: TranslationFile[], filesToParse: string[], options?: Options, componentFunctions?:
|
|
13
|
+
export declare const checkUnusedKeys: (translationFiles: TranslationFile[], filesToParse: string[], options?: Options, componentFunctions?: string[]) => Promise<CheckResult | undefined>;
|
|
14
|
+
export declare const checkUndefinedKeys: (source: TranslationFile[], filesToParse: string[], options?: Options, componentFunctions?: string[]) => Promise<CheckResult | undefined>;
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const findInvalidi18nTranslations_1 = require("./utils/findInvalidi18nTranslatio
|
|
|
10
10
|
const cli_lib_1 = require("@formatjs/cli-lib");
|
|
11
11
|
const nextIntlSrcParser_1 = require("./utils/nextIntlSrcParser");
|
|
12
12
|
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
13
14
|
const ParseFormats = ["react-intl", "i18next", "next-intl"];
|
|
14
15
|
const checkInvalidTranslations = (source, targets, options = { format: "icu" }) => {
|
|
15
16
|
return options.format === "i18next"
|
|
@@ -28,16 +29,14 @@ const checkTranslations = (source, targets, options = { format: "icu", checks: [
|
|
|
28
29
|
const hasMissingKeys = checks.includes("missingKeys");
|
|
29
30
|
const hasInvalidKeys = checks.includes("invalidKeys");
|
|
30
31
|
source.forEach(({ name, content }) => {
|
|
31
|
-
const files = targets
|
|
32
|
+
const files = Object.fromEntries(targets
|
|
32
33
|
.filter(({ reference }) => reference === name)
|
|
33
|
-
.
|
|
34
|
-
return Object.assign(obj, { [key]: content });
|
|
35
|
-
}, {});
|
|
34
|
+
.map(({ name, content }) => [name, content]));
|
|
36
35
|
if (hasMissingKeys) {
|
|
37
|
-
|
|
36
|
+
merge(missingKeys, (0, exports.checkMissingTranslations)(content, files));
|
|
38
37
|
}
|
|
39
38
|
if (hasInvalidKeys) {
|
|
40
|
-
|
|
39
|
+
merge(invalidKeys, (0, exports.checkInvalidTranslations)(content, files, options));
|
|
41
40
|
}
|
|
42
41
|
});
|
|
43
42
|
return {
|
|
@@ -46,6 +45,11 @@ const checkTranslations = (source, targets, options = { format: "icu", checks: [
|
|
|
46
45
|
};
|
|
47
46
|
};
|
|
48
47
|
exports.checkTranslations = checkTranslations;
|
|
48
|
+
function merge(left, right) {
|
|
49
|
+
for (let [k, v] of Object.entries(right)) {
|
|
50
|
+
left[k] = (left?.[k] ?? []).concat(v);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
49
53
|
const checkUnusedKeys = async (translationFiles, filesToParse, options = {
|
|
50
54
|
format: "react-intl",
|
|
51
55
|
checks: [],
|
|
@@ -68,7 +72,7 @@ const checkUnusedKeys = async (translationFiles, filesToParse, options = {
|
|
|
68
72
|
};
|
|
69
73
|
exports.checkUnusedKeys = checkUnusedKeys;
|
|
70
74
|
const findUnusedReactIntlTranslations = async (translationFiles, filesToParse) => {
|
|
71
|
-
|
|
75
|
+
const unusedKeys = {};
|
|
72
76
|
const extracted = await (0, cli_lib_1.extract)(filesToParse, {});
|
|
73
77
|
const extractedResultSet = new Set(Object.keys(JSON.parse(extracted)));
|
|
74
78
|
translationFiles.forEach(({ name, content }) => {
|
|
@@ -79,12 +83,12 @@ const findUnusedReactIntlTranslations = async (translationFiles, filesToParse) =
|
|
|
79
83
|
found.push(keyInSource);
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
|
-
|
|
86
|
+
unusedKeys[name] = found;
|
|
83
87
|
});
|
|
84
88
|
return unusedKeys;
|
|
85
89
|
};
|
|
86
90
|
const findUnusedI18NextTranslations = async (source, filesToParse, componentFunctions = []) => {
|
|
87
|
-
|
|
91
|
+
const unusedKeys = {};
|
|
88
92
|
const { extractedResult, skippableKeys } = await getI18NextKeysInCode(filesToParse, componentFunctions);
|
|
89
93
|
const extractedResultSet = new Set(extractedResult.map(({ key }) => key));
|
|
90
94
|
source.forEach(({ name, content }) => {
|
|
@@ -101,12 +105,12 @@ const findUnusedI18NextTranslations = async (source, filesToParse, componentFunc
|
|
|
101
105
|
found.push(keyInSource);
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
|
-
|
|
108
|
+
unusedKeys[name] = found;
|
|
105
109
|
});
|
|
106
110
|
return unusedKeys;
|
|
107
111
|
};
|
|
108
112
|
const findUnusedNextIntlTranslations = async (translationFiles, filesToParse) => {
|
|
109
|
-
|
|
113
|
+
const unusedKeys = {};
|
|
110
114
|
const extracted = (0, nextIntlSrcParser_1.extract)(filesToParse);
|
|
111
115
|
const dynamicNamespaces = extracted.flatMap((namespace) => {
|
|
112
116
|
if (namespace.meta.dynamic) {
|
|
@@ -139,7 +143,7 @@ const findUnusedNextIntlTranslations = async (translationFiles, filesToParse) =>
|
|
|
139
143
|
found.push(keyInSource);
|
|
140
144
|
}
|
|
141
145
|
}
|
|
142
|
-
|
|
146
|
+
unusedKeys[name] = found;
|
|
143
147
|
});
|
|
144
148
|
return unusedKeys;
|
|
145
149
|
};
|
|
@@ -174,8 +178,11 @@ const findUndefinedReactIntlKeys = async (translationFiles, filesToParse) => {
|
|
|
174
178
|
let undefinedKeys = {};
|
|
175
179
|
Object.entries(JSON.parse(extractedResult)).forEach(([key, meta]) => {
|
|
176
180
|
if (!sourceKeys.has(key)) {
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
const data = meta;
|
|
182
|
+
if (!("file" in data) || typeof data.file !== "string") {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const file = path_1.default.normalize(data.file);
|
|
179
186
|
if (!undefinedKeys[file]) {
|
|
180
187
|
undefinedKeys[file] = [];
|
|
181
188
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export type Translation = Record<string, unknown>;
|
|
2
2
|
export type CheckResult = Record<string, string[]>;
|
|
3
|
+
export type InvalidTranslationEntry = {
|
|
4
|
+
key: string;
|
|
5
|
+
msg: string;
|
|
6
|
+
};
|
|
7
|
+
export type InvalidTranslationsResult = Record<string, InvalidTranslationEntry[]>;
|
|
3
8
|
export type TranslationFile = {
|
|
4
9
|
reference: string | null;
|
|
5
10
|
name: string;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { MessageFormatElement } from "@formatjs/icu-messageformat-parser";
|
|
2
|
-
import { Translation } from "../types";
|
|
3
|
-
export declare const findInvalidTranslations: (source: Translation, files: Record<string, Translation>) =>
|
|
4
|
-
export declare const compareTranslationFiles: (a: Translation, b: Translation) =>
|
|
5
|
-
key: string;
|
|
6
|
-
msg: string;
|
|
7
|
-
}[];
|
|
2
|
+
import { InvalidTranslationEntry, InvalidTranslationsResult, Translation } from "../types";
|
|
3
|
+
export declare const findInvalidTranslations: (source: Translation, files: Record<string, Translation>) => InvalidTranslationsResult;
|
|
4
|
+
export declare const compareTranslationFiles: (a: Translation, b: Translation) => InvalidTranslationEntry[];
|
|
8
5
|
export declare const hasDiff: (a: MessageFormatElement[], b: MessageFormatElement[]) => boolean;
|
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.hasDiff = exports.compareTranslationFiles = exports.findInvalidTranslations = void 0;
|
|
4
4
|
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
5
|
const findInvalidTranslations = (source, files) => {
|
|
6
|
-
|
|
6
|
+
const differences = {};
|
|
7
7
|
if (Object.keys(files).length === 0) {
|
|
8
8
|
return differences;
|
|
9
9
|
}
|
|
10
10
|
for (const [lang, file] of Object.entries(files)) {
|
|
11
11
|
const result = (0, exports.compareTranslationFiles)(source, file);
|
|
12
12
|
if (result.length > 0) {
|
|
13
|
-
differences
|
|
13
|
+
differences[lang] = result;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
return differences;
|
|
@@ -27,7 +27,7 @@ const sortParsedKeys = (a, b) => {
|
|
|
27
27
|
return a.type - b.type;
|
|
28
28
|
};
|
|
29
29
|
const compareTranslationFiles = (a, b) => {
|
|
30
|
-
|
|
30
|
+
const diffs = [];
|
|
31
31
|
for (const key in a) {
|
|
32
32
|
if (b[key] === undefined) {
|
|
33
33
|
continue;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
import { MessageFormatElement } from "./i18NextParser";
|
|
8
|
-
import { Translation } from "../types";
|
|
9
|
-
export declare const findInvalid18nTranslations: (source: Translation, targets: Record<string, Translation>) =>
|
|
10
|
-
export declare const compareTranslationFiles: (a: Translation, b: Translation) =>
|
|
8
|
+
import { InvalidTranslationEntry, InvalidTranslationsResult, Translation } from "../types";
|
|
9
|
+
export declare const findInvalid18nTranslations: (source: Translation, targets: Record<string, Translation>) => InvalidTranslationsResult;
|
|
10
|
+
export declare const compareTranslationFiles: (a: Translation, b: Translation) => InvalidTranslationEntry[];
|
|
11
11
|
export declare const hasDiff: (a: MessageFormatElement[], b: MessageFormatElement[]) => boolean;
|
|
@@ -16,7 +16,7 @@ const findInvalid18nTranslations = (source, targets) => {
|
|
|
16
16
|
for (const [lang, file] of Object.entries(targets)) {
|
|
17
17
|
const result = (0, exports.compareTranslationFiles)(source, file);
|
|
18
18
|
if (result.length > 0) {
|
|
19
|
-
differences
|
|
19
|
+
differences[lang] = result;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
return differences;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Translation } from "../types";
|
|
2
|
-
export declare const findMissingKeys: (source: Translation, targets: Record<string, Translation>) =>
|
|
2
|
+
export declare const findMissingKeys: (source: Translation, targets: Record<string, Translation>) => Record<string, string[]>;
|
|
3
3
|
export declare const compareTranslationFiles: (a: Translation, b: Translation) => string[];
|
|
@@ -6,7 +6,7 @@ const findMissingKeys = (source, targets) => {
|
|
|
6
6
|
for (const [lang, file] of Object.entries(targets)) {
|
|
7
7
|
const result = (0, exports.compareTranslationFiles)(source, file);
|
|
8
8
|
if (result.length > 0) {
|
|
9
|
-
differences
|
|
9
|
+
differences[lang] = result;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
return differences;
|