@lingual/i18n-check 0.9.0 → 0.9.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.d.ts +2 -0
- package/dist/bin/index.js +286 -0
- package/dist/errorReporters.d.ts +13 -0
- package/dist/errorReporters.js +78 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +345 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.js +2 -0
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.js +12 -0
- package/dist/utils/findInvalidI18NextTranslations.d.ts +11 -0
- package/dist/utils/findInvalidI18NextTranslations.js +192 -0
- package/dist/utils/findInvalidTranslations.d.ts +16 -0
- package/dist/utils/findInvalidTranslations.js +239 -0
- package/dist/utils/findMissingKeys.d.ts +4 -0
- package/dist/utils/findMissingKeys.js +55 -0
- package/dist/utils/flattenTranslations.d.ts +3 -0
- package/dist/utils/flattenTranslations.js +33 -0
- package/dist/utils/i18NextParser.d.ts +37 -0
- package/dist/utils/i18NextParser.js +104 -0
- package/dist/utils/i18NextSrcParser.d.ts +35 -0
- package/dist/utils/i18NextSrcParser.js +718 -0
- package/dist/utils/nextIntlSrcParser.d.ts +8 -0
- package/dist/utils/nextIntlSrcParser.js +432 -0
- package/package.json +3 -2
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_process_1 = require("node:process");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const commander_1 = require("commander");
|
|
11
|
+
const glob_1 = require("glob");
|
|
12
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
const errorReporters_1 = require("../errorReporters");
|
|
15
|
+
const flattenTranslations_1 = require("../utils/flattenTranslations");
|
|
16
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
const findInvalidTranslations_1 = require("../utils/findInvalidTranslations");
|
|
18
|
+
const version = require('../../package.json').version;
|
|
19
|
+
commander_1.program
|
|
20
|
+
.version(version)
|
|
21
|
+
.option('-l, --locales <locales...>', 'name of the directory containing the locales to validate')
|
|
22
|
+
.option('-s, --source <locale>', 'the source locale to validate against')
|
|
23
|
+
.option('-f, --format <type>', 'define the specific format: i18next, react-intl or next-intl')
|
|
24
|
+
.option('-c, --check <checks...>', 'this option is deprecated - use -o or --only instead')
|
|
25
|
+
.option('-o, --only <only...>', 'define the specific checks you want to run: invalidKeys, missingKeys, unused, undefined. By default the check will validate against missing and invalid keys, i.e. --only invalidKeys,missingKeys')
|
|
26
|
+
.option('-r, --reporter <style>', 'define the reporting style: standard or summary')
|
|
27
|
+
.option('-e, --exclude <exclude...>', 'define the file(s) and/or folders(s) that should be excluded from the check')
|
|
28
|
+
.option('-i, --ignore <ignore...>', 'define the key(s) or group of keys (i.e. `some.namespace.*`) that should be excluded from the check')
|
|
29
|
+
.option('-u, --unused <paths...>', 'define the source path(s) to find all unused and undefined keys')
|
|
30
|
+
.option('--parser-component-functions <components...>', 'a list of component names to parse when using the --unused option')
|
|
31
|
+
.parse();
|
|
32
|
+
const getCheckOptions = () => {
|
|
33
|
+
const checkOption = commander_1.program.getOptionValue('only') || commander_1.program.getOptionValue('check');
|
|
34
|
+
if (commander_1.program.getOptionValue('check')) {
|
|
35
|
+
console.log(chalk_1.default.yellow('The --check option has been deprecated, use the --only option instead.'));
|
|
36
|
+
}
|
|
37
|
+
if (!checkOption) {
|
|
38
|
+
return errorReporters_1.CheckOptions;
|
|
39
|
+
}
|
|
40
|
+
const checks = checkOption.filter((check) => errorReporters_1.CheckOptions.includes(check.trim()));
|
|
41
|
+
return checks.length > 0 ? checks : errorReporters_1.CheckOptions;
|
|
42
|
+
};
|
|
43
|
+
const isSource = (fileInfo, srcPath) => {
|
|
44
|
+
return (fileInfo.path.some((path) => path.toLowerCase() === srcPath.toLowerCase()) || fileInfo.name.toLowerCase().slice(0, -5) === srcPath.toLowerCase());
|
|
45
|
+
};
|
|
46
|
+
const main = async () => {
|
|
47
|
+
const start = performance.now();
|
|
48
|
+
const srcPath = commander_1.program.getOptionValue('source');
|
|
49
|
+
const localePath = commander_1.program.getOptionValue('locales');
|
|
50
|
+
const format = commander_1.program.getOptionValue('format');
|
|
51
|
+
const exclude = commander_1.program.getOptionValue('exclude');
|
|
52
|
+
const ignore = commander_1.program.getOptionValue('ignore');
|
|
53
|
+
const unusedSrcPath = commander_1.program.getOptionValue('unused');
|
|
54
|
+
const componentFunctions = commander_1.program.getOptionValue('parserComponentFunctions');
|
|
55
|
+
if (!srcPath) {
|
|
56
|
+
console.log(chalk_1.default.red('Source not found. Please provide a valid source locale, i.e. -s en-US'));
|
|
57
|
+
(0, node_process_1.exit)(1);
|
|
58
|
+
}
|
|
59
|
+
if (!localePath || localePath.length === 0) {
|
|
60
|
+
console.log(chalk_1.default.red('Locale file(s) not found. Please provide valid locale file(s), i.e. -locales translations/'));
|
|
61
|
+
(0, node_process_1.exit)(1);
|
|
62
|
+
}
|
|
63
|
+
const excludedPaths = exclude ?? [];
|
|
64
|
+
const localePathFolders = localePath;
|
|
65
|
+
const isMultiFolders = localePathFolders.length > 1;
|
|
66
|
+
const srcFiles = [];
|
|
67
|
+
const targetFiles = [];
|
|
68
|
+
const pattern = isMultiFolders
|
|
69
|
+
? `{${localePath.join(',').trim()}}/**/*.{json,yaml,yml}`
|
|
70
|
+
: `${localePath.join(',').trim()}/**/*.{json,yaml,yml}`;
|
|
71
|
+
const files = await (0, glob_1.glob)(pattern, {
|
|
72
|
+
ignore: ['node_modules/**'].concat(excludedPaths),
|
|
73
|
+
windowsPathsNoEscape: true,
|
|
74
|
+
});
|
|
75
|
+
console.log('i18n translations checker');
|
|
76
|
+
console.log(chalk_1.default.gray(`Source: ${srcPath}`));
|
|
77
|
+
if (format) {
|
|
78
|
+
console.log(chalk_1.default.blackBright(`Selected format is: ${format}`));
|
|
79
|
+
}
|
|
80
|
+
const options = {
|
|
81
|
+
checks: getCheckOptions(),
|
|
82
|
+
format: format ?? undefined,
|
|
83
|
+
ignore,
|
|
84
|
+
};
|
|
85
|
+
const fileInfos = [];
|
|
86
|
+
files.sort().forEach((file) => {
|
|
87
|
+
const filePath = file.split(node_path_1.default.sep);
|
|
88
|
+
const name = filePath.pop() ?? '';
|
|
89
|
+
const extension = name.split('.').pop() ?? 'json';
|
|
90
|
+
fileInfos.push({
|
|
91
|
+
extension,
|
|
92
|
+
file,
|
|
93
|
+
name,
|
|
94
|
+
path: filePath,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
fileInfos.forEach(({ extension, file, name, path }) => {
|
|
98
|
+
let rawContent;
|
|
99
|
+
if (extension === 'yaml') {
|
|
100
|
+
rawContent = js_yaml_1.default.load(node_fs_1.default.readFileSync(file, 'utf-8'));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
rawContent = JSON.parse(node_fs_1.default.readFileSync(file, 'utf-8'));
|
|
104
|
+
}
|
|
105
|
+
const content = (0, flattenTranslations_1.flattenTranslations)(rawContent);
|
|
106
|
+
if (isSource({ file, name, path }, srcPath)) {
|
|
107
|
+
srcFiles.push({
|
|
108
|
+
reference: null,
|
|
109
|
+
name: file,
|
|
110
|
+
content,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const fullPath = path.join('-');
|
|
115
|
+
const reference = fileInfos.find((fileInfo) => {
|
|
116
|
+
if (!isSource(fileInfo, srcPath)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
if (fileInfo.path.join('-') === fullPath) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
// Check if the folder path matches - ignoring the last folder
|
|
123
|
+
// Then check if the file names are the same
|
|
124
|
+
// Example folder structure:
|
|
125
|
+
// path/to/locales/
|
|
126
|
+
// en-US/
|
|
127
|
+
// one.json
|
|
128
|
+
// two.json
|
|
129
|
+
// three.json
|
|
130
|
+
// de-DE/
|
|
131
|
+
// one.json
|
|
132
|
+
// two.json
|
|
133
|
+
// three.json
|
|
134
|
+
//
|
|
135
|
+
// Referencing: `path/to/locales/en-US/one.json`, `path/to/locales/de-DE/one.json`
|
|
136
|
+
// Non Referencing: `path/to/locales/en-US/one.json`, `path/to/other/locales/de-DE/one.json`
|
|
137
|
+
if (fileInfo.path.slice(0, fileInfo.path.length - 1).join('-') ===
|
|
138
|
+
path.slice(0, path.length - 1).join('-')) {
|
|
139
|
+
return fileInfo.name === name;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
});
|
|
143
|
+
if (reference) {
|
|
144
|
+
targetFiles.push({
|
|
145
|
+
reference: reference.file,
|
|
146
|
+
name: file,
|
|
147
|
+
content,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
if (srcFiles.length === 0) {
|
|
153
|
+
console.log(chalk_1.default.red('Source not found. Please provide a valid source locale, i.e. -s en-US'));
|
|
154
|
+
(0, node_process_1.exit)(1);
|
|
155
|
+
}
|
|
156
|
+
if ((options.checks.includes('missingKeys') ||
|
|
157
|
+
options.checks.includes('invalidKeys')) &&
|
|
158
|
+
targetFiles.length === 0) {
|
|
159
|
+
// Remove missingKeys and invalidKeys from checks since they require multiple files
|
|
160
|
+
options.checks = options.checks.filter((check) => check !== 'missingKeys' && check !== 'invalidKeys');
|
|
161
|
+
console.log(chalk_1.default.yellow('\nOnly one locale file found. Skipping missingKeys and invalidKeys checks.\n'));
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const result = (0, __1.checkTranslations)(srcFiles, targetFiles, options);
|
|
165
|
+
let unusedKeyResult = undefined;
|
|
166
|
+
let undefinedKeyResult = undefined;
|
|
167
|
+
printTranslationResult(result);
|
|
168
|
+
if (unusedSrcPath) {
|
|
169
|
+
const isMultiUnusedFolders = unusedSrcPath.length > 1;
|
|
170
|
+
const pattern = isMultiUnusedFolders
|
|
171
|
+
? `{${unusedSrcPath.join(',').trim()}}/**/*.{js,jsx,ts,tsx}`
|
|
172
|
+
: `${unusedSrcPath.join(',').trim()}/**/*.{js,jsx,ts,tsx}`;
|
|
173
|
+
const filesToParse = (0, glob_1.globSync)(pattern, {
|
|
174
|
+
ignore: ['node_modules/**'],
|
|
175
|
+
windowsPathsNoEscape: true,
|
|
176
|
+
});
|
|
177
|
+
const unusedKeys = await (0, __1.checkUnusedKeys)(srcFiles, filesToParse, options, componentFunctions);
|
|
178
|
+
printUnusedKeysResult({ unusedKeys });
|
|
179
|
+
unusedKeyResult = unusedKeys;
|
|
180
|
+
const undefinedKeys = await (0, __1.checkUndefinedKeys)(srcFiles, filesToParse, options, componentFunctions);
|
|
181
|
+
printUndefinedKeysResult({
|
|
182
|
+
undefinedKeys,
|
|
183
|
+
});
|
|
184
|
+
undefinedKeyResult = undefinedKeys;
|
|
185
|
+
}
|
|
186
|
+
const end = performance.now();
|
|
187
|
+
console.log(chalk_1.default.green(`\nDone in ${Math.round(((end - start) * 100) / 1000) / 100}s.`));
|
|
188
|
+
if ((result.missingKeys && Object.keys(result.missingKeys).length > 0) ||
|
|
189
|
+
(result.invalidKeys && Object.keys(result.invalidKeys).length > 0) ||
|
|
190
|
+
(unusedKeyResult && hasKeys(unusedKeyResult)) ||
|
|
191
|
+
(undefinedKeyResult && hasKeys(undefinedKeyResult))) {
|
|
192
|
+
(0, node_process_1.exit)(1);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
(0, node_process_1.exit)(0);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
let errorMessage = "\nError: Can't validate translations. Check if the format is supported or specify the translation format i.e. -f i18next";
|
|
200
|
+
// Use enhanced error message if available
|
|
201
|
+
if (e instanceof findInvalidTranslations_1.CheckError) {
|
|
202
|
+
errorMessage = `\n${e.message}`;
|
|
203
|
+
// Check if the error has location information (from ICU parser)
|
|
204
|
+
if (e.location) {
|
|
205
|
+
errorMessage += `\nLocation: Line ${e.location.start.line}, Column ${e.location.start.column}`;
|
|
206
|
+
}
|
|
207
|
+
// Check if the error has originalMessage (from ICU parser)
|
|
208
|
+
if (e.originalMessage != null) {
|
|
209
|
+
errorMessage += `\nProblematic translation: "${e.originalMessage}"`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
console.log(chalk_1.default.red(errorMessage));
|
|
213
|
+
(0, node_process_1.exit)(1);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const printTranslationResult = ({ missingKeys, invalidKeys, }) => {
|
|
217
|
+
const reporter = commander_1.program.getOptionValue('reporter');
|
|
218
|
+
const isSummary = reporter === 'summary';
|
|
219
|
+
if (missingKeys && Object.keys(missingKeys).length > 0) {
|
|
220
|
+
console.log(chalk_1.default.red('\nFound missing keys!'));
|
|
221
|
+
if (isSummary) {
|
|
222
|
+
console.log(chalk_1.default.red((0, errorReporters_1.formatSummaryTable)(missingKeys)));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const table = (0, errorReporters_1.formatCheckResultTable)(missingKeys);
|
|
226
|
+
console.log(chalk_1.default.red(table));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else if (missingKeys) {
|
|
230
|
+
console.log(chalk_1.default.green('\nNo missing keys found!'));
|
|
231
|
+
}
|
|
232
|
+
if (invalidKeys && Object.keys(invalidKeys).length > 0) {
|
|
233
|
+
console.log(chalk_1.default.red('\nFound invalid keys!'));
|
|
234
|
+
if (isSummary) {
|
|
235
|
+
console.log(chalk_1.default.red((0, errorReporters_1.formatSummaryTable)(invalidKeys)));
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
const table = (0, errorReporters_1.formatInvalidTranslationsResultTable)(invalidKeys);
|
|
239
|
+
console.log(chalk_1.default.red(table));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else if (invalidKeys) {
|
|
243
|
+
console.log(chalk_1.default.green('\nNo invalid translations found!'));
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const printUnusedKeysResult = ({ unusedKeys, }) => {
|
|
247
|
+
const reporter = commander_1.program.getOptionValue('reporter');
|
|
248
|
+
const isSummary = reporter === 'summary';
|
|
249
|
+
if (unusedKeys && hasKeys(unusedKeys)) {
|
|
250
|
+
console.log(chalk_1.default.red('\nFound unused keys!'));
|
|
251
|
+
if (isSummary) {
|
|
252
|
+
console.log(chalk_1.default.red((0, errorReporters_1.formatSummaryTable)(unusedKeys)));
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
console.log(chalk_1.default.red((0, errorReporters_1.formatCheckResultTable)(unusedKeys)));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else if (unusedKeys) {
|
|
259
|
+
console.log(chalk_1.default.green('\nNo unused keys found!'));
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const printUndefinedKeysResult = ({ undefinedKeys, }) => {
|
|
263
|
+
const reporter = commander_1.program.getOptionValue('reporter');
|
|
264
|
+
const isSummary = reporter === 'summary';
|
|
265
|
+
if (undefinedKeys && hasKeys(undefinedKeys)) {
|
|
266
|
+
console.log(chalk_1.default.red('\nFound undefined keys!'));
|
|
267
|
+
if (isSummary) {
|
|
268
|
+
console.log(chalk_1.default.red((0, errorReporters_1.formatSummaryTable)(undefinedKeys)));
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
console.log(chalk_1.default.red((0, errorReporters_1.formatCheckResultTable)(undefinedKeys)));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else if (undefinedKeys) {
|
|
275
|
+
console.log(chalk_1.default.green('\nNo undefined keys found!'));
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const hasKeys = (checkResult) => {
|
|
279
|
+
for (const [_, keys] of Object.entries(checkResult)) {
|
|
280
|
+
if (keys.length > 0) {
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return false;
|
|
285
|
+
};
|
|
286
|
+
main();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CheckResult, InvalidTranslationsResult } from './types';
|
|
2
|
+
export type StandardReporter = {
|
|
3
|
+
file: string;
|
|
4
|
+
key: string;
|
|
5
|
+
msg?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const CheckOptions: string[];
|
|
8
|
+
export type Context = (typeof CheckOptions)[number];
|
|
9
|
+
export declare const contextMapping: Record<Context, 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;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.contextMapping = exports.CheckOptions = void 0;
|
|
4
|
+
exports.formatSummaryTable = formatSummaryTable;
|
|
5
|
+
exports.formatTable = formatTable;
|
|
6
|
+
exports.formatCheckResultTable = formatCheckResultTable;
|
|
7
|
+
exports.formatInvalidTranslationsResultTable = formatInvalidTranslationsResultTable;
|
|
8
|
+
exports.CheckOptions = [
|
|
9
|
+
'invalidKeys',
|
|
10
|
+
'missingKeys',
|
|
11
|
+
'unused',
|
|
12
|
+
'undefined',
|
|
13
|
+
];
|
|
14
|
+
exports.contextMapping = {
|
|
15
|
+
invalidKeys: 'invalid',
|
|
16
|
+
missingKeys: 'missing',
|
|
17
|
+
unused: 'unused',
|
|
18
|
+
undefined: 'undefined',
|
|
19
|
+
};
|
|
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
|
+
}
|
|
28
|
+
return [[['file', 'total']], rows];
|
|
29
|
+
};
|
|
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
|
+
}
|
|
39
|
+
}
|
|
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));
|
|
46
|
+
}
|
|
47
|
+
lines.push(formatSeparatorRow(colWidths, '├┼┤'));
|
|
48
|
+
}
|
|
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
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CheckResult, InvalidTranslationsResult, Options, Translation, TranslationFile } from './types';
|
|
2
|
+
export declare const checkInvalidTranslations: (source: Translation, targets: Record<string, Translation>, options?: Options) => InvalidTranslationsResult;
|
|
3
|
+
export declare const checkMissingTranslations: (source: Translation, targets: Record<string, Translation>, options: Options) => CheckResult;
|
|
4
|
+
export declare const checkTranslations: (source: TranslationFile[], targets: TranslationFile[], options?: Options) => {
|
|
5
|
+
missingKeys: CheckResult | undefined;
|
|
6
|
+
invalidKeys: InvalidTranslationsResult | undefined;
|
|
7
|
+
};
|
|
8
|
+
export declare const checkUnusedKeys: (translationFiles: TranslationFile[], filesToParse: string[], options?: Options, componentFunctions?: string[]) => Promise<CheckResult | undefined>;
|
|
9
|
+
export declare const checkUndefinedKeys: (source: TranslationFile[], filesToParse: string[], options?: Options, componentFunctions?: string[]) => Promise<CheckResult | undefined>;
|