@lingual/i18n-check 0.8.13 → 0.8.15
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/{src/bin → bin}/index.js +16 -3
- package/dist/{src/utils → utils}/findInvalidTranslations.d.ts +11 -0
- package/dist/{src/utils → utils}/findInvalidTranslations.js +56 -9
- package/package.json +2 -2
- package/dist/vitest.bin.config.d.ts +0 -2
- package/dist/vitest.bin.config.js +0 -14
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -12
- /package/dist/{src/bin → bin}/index.d.ts +0 -0
- /package/dist/{src/errorReporters.d.ts → errorReporters.d.ts} +0 -0
- /package/dist/{src/errorReporters.js → errorReporters.js} +0 -0
- /package/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{src/index.js → index.js} +0 -0
- /package/dist/{src/types.d.ts → types.d.ts} +0 -0
- /package/dist/{src/types.js → types.js} +0 -0
- /package/dist/{src/utils → utils}/constants.d.ts +0 -0
- /package/dist/{src/utils → utils}/constants.js +0 -0
- /package/dist/{src/utils → utils}/findInvalidI18NextTranslations.d.ts +0 -0
- /package/dist/{src/utils → utils}/findInvalidI18NextTranslations.js +0 -0
- /package/dist/{src/utils → utils}/findMissingKeys.d.ts +0 -0
- /package/dist/{src/utils → utils}/findMissingKeys.js +0 -0
- /package/dist/{src/utils → utils}/flattenTranslations.d.ts +0 -0
- /package/dist/{src/utils → utils}/flattenTranslations.js +0 -0
- /package/dist/{src/utils → utils}/i18NextParser.d.ts +0 -0
- /package/dist/{src/utils → utils}/i18NextParser.js +0 -0
- /package/dist/{src/utils → utils}/nextIntlSrcParser.d.ts +0 -0
- /package/dist/{src/utils → utils}/nextIntlSrcParser.js +0 -0
|
@@ -14,6 +14,7 @@ const __1 = require("..");
|
|
|
14
14
|
const errorReporters_1 = require("../errorReporters");
|
|
15
15
|
const flattenTranslations_1 = require("../utils/flattenTranslations");
|
|
16
16
|
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
const findInvalidTranslations_1 = require("../utils/findInvalidTranslations");
|
|
17
18
|
const version = require('../../package.json').version;
|
|
18
19
|
commander_1.program
|
|
19
20
|
.version(version)
|
|
@@ -156,7 +157,7 @@ const main = async () => {
|
|
|
156
157
|
options.checks.includes('invalidKeys')) &&
|
|
157
158
|
targetFiles.length === 0) {
|
|
158
159
|
// Remove missingKeys and invalidKeys from checks since they require multiple files
|
|
159
|
-
options.checks = options.checks.filter(check => check !== 'missingKeys' && check !== 'invalidKeys');
|
|
160
|
+
options.checks = options.checks.filter((check) => check !== 'missingKeys' && check !== 'invalidKeys');
|
|
160
161
|
console.log(chalk_1.default.yellow('\nOnly one locale file found. Skipping missingKeys and invalidKeys checks.\n'));
|
|
161
162
|
}
|
|
162
163
|
try {
|
|
@@ -193,10 +194,22 @@ const main = async () => {
|
|
|
193
194
|
else {
|
|
194
195
|
(0, node_process_1.exit)(0);
|
|
195
196
|
}
|
|
196
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
197
197
|
}
|
|
198
198
|
catch (e) {
|
|
199
|
-
|
|
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));
|
|
200
213
|
(0, node_process_1.exit)(1);
|
|
201
214
|
}
|
|
202
215
|
};
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { MessageFormatElement } from '@formatjs/icu-messageformat-parser';
|
|
2
2
|
import { InvalidTranslationEntry, InvalidTranslationsResult, Translation } from '../types';
|
|
3
|
+
type Location = {
|
|
4
|
+
start: {
|
|
5
|
+
line: number;
|
|
6
|
+
column: number;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare class CheckError extends Error {
|
|
10
|
+
location?: Location;
|
|
11
|
+
originalMessage?: string;
|
|
12
|
+
}
|
|
3
13
|
export declare const findInvalidTranslations: (source: Translation, files: Record<string, Translation>) => InvalidTranslationsResult;
|
|
4
14
|
export declare const compareTranslationFiles: (a: Translation, b: Translation) => InvalidTranslationEntry[];
|
|
5
15
|
export declare const hasDiff: (a: MessageFormatElement[], b: MessageFormatElement[]) => boolean;
|
|
16
|
+
export {};
|
|
@@ -1,16 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasDiff = exports.compareTranslationFiles = exports.findInvalidTranslations = void 0;
|
|
3
|
+
exports.hasDiff = exports.compareTranslationFiles = exports.findInvalidTranslations = exports.CheckError = void 0;
|
|
4
4
|
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
|
+
class CheckError extends Error {
|
|
6
|
+
}
|
|
7
|
+
exports.CheckError = CheckError;
|
|
8
|
+
function isLocation(value) {
|
|
9
|
+
return (typeof value === 'object' &&
|
|
10
|
+
value != null &&
|
|
11
|
+
'start' in value &&
|
|
12
|
+
typeof value.start === 'object' &&
|
|
13
|
+
value.start != null &&
|
|
14
|
+
'line' in value.start &&
|
|
15
|
+
typeof value.start.line === 'number' &&
|
|
16
|
+
'column' in value.start &&
|
|
17
|
+
typeof value.start.column === 'number');
|
|
18
|
+
}
|
|
5
19
|
const findInvalidTranslations = (source, files) => {
|
|
6
20
|
const differences = {};
|
|
7
21
|
if (Object.keys(files).length === 0) {
|
|
8
22
|
return differences;
|
|
9
23
|
}
|
|
10
24
|
for (const [lang, file] of Object.entries(files)) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
try {
|
|
26
|
+
const result = (0, exports.compareTranslationFiles)(source, file);
|
|
27
|
+
if (result.length > 0) {
|
|
28
|
+
differences[lang] = result;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
// Re-throw with file context
|
|
33
|
+
const enhancedError = new CheckError(`Error in translation file "${lang}": ${error instanceof Error ? error.message : String(error)}`);
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
if ('location' in error && isLocation(error.location)) {
|
|
36
|
+
enhancedError.location = error.location;
|
|
37
|
+
}
|
|
38
|
+
if ('originalMessage' in error &&
|
|
39
|
+
typeof error.originalMessage === 'string') {
|
|
40
|
+
enhancedError.originalMessage = error.originalMessage;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
throw enhancedError;
|
|
14
44
|
}
|
|
15
45
|
}
|
|
16
46
|
return differences;
|
|
@@ -32,11 +62,28 @@ const compareTranslationFiles = (a, b) => {
|
|
|
32
62
|
if (b[key] === undefined) {
|
|
33
63
|
continue;
|
|
34
64
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
try {
|
|
66
|
+
const parsedTranslationA = (0, icu_messageformat_parser_1.parse)(String(a[key]));
|
|
67
|
+
const parsedTranslationB = (0, icu_messageformat_parser_1.parse)(String(b[key]));
|
|
68
|
+
if ((0, exports.hasDiff)(parsedTranslationA, parsedTranslationB)) {
|
|
69
|
+
const msg = getErrorMessage(parsedTranslationA, parsedTranslationB);
|
|
70
|
+
diffs.push({ key, msg });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// Re-throw with key context and preserve location/originalMessage
|
|
75
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
76
|
+
const enhancedError = new CheckError(`Failed to parse translation key "${key}": ${errorMessage === 'INVALID_TAG' ? 'Invalid ICU message format tags found in translation content' : errorMessage}`);
|
|
77
|
+
if (error instanceof Error) {
|
|
78
|
+
if ('location' in error && isLocation(error.location)) {
|
|
79
|
+
enhancedError.location = error.location;
|
|
80
|
+
}
|
|
81
|
+
if ('originalMessage' in error &&
|
|
82
|
+
typeof error.originalMessage === 'string') {
|
|
83
|
+
enhancedError.originalMessage = error.originalMessage;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
throw enhancedError;
|
|
40
87
|
}
|
|
41
88
|
}
|
|
42
89
|
return diffs;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingual/i18n-check",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.15",
|
|
4
4
|
"description": "i18n translation messages check",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"lint:fix": "eslint src --fix ",
|
|
17
17
|
"check-format": "prettier --check './{src,translations}/**/*.{js,jsx,ts,tsx,json,html,css}'",
|
|
18
18
|
"test": "vitest run",
|
|
19
|
-
"test:cli": "
|
|
19
|
+
"test:cli": "pnpm build && vitest --config vitest.bin.config.ts run src/bin/index.test.ts"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"dist/",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
// vitest.config.ts
|
|
7
|
-
const config_1 = require("vitest/config");
|
|
8
|
-
const vitest_config_1 = __importDefault(require("./vitest.config"));
|
|
9
|
-
exports.default = (0, config_1.defineConfig)({
|
|
10
|
-
...vitest_config_1.default,
|
|
11
|
-
test: {
|
|
12
|
-
exclude: ['node_modules', 'dist'],
|
|
13
|
-
},
|
|
14
|
-
});
|
package/dist/vitest.config.d.ts
DELETED
package/dist/vitest.config.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
// vitest.config.ts
|
|
4
|
-
const config_1 = require("vitest/config");
|
|
5
|
-
exports.default = (0, config_1.defineConfig)({
|
|
6
|
-
test: {
|
|
7
|
-
globals: true, // (optional) use Jest-like globals like `describe`, `test`, etc.
|
|
8
|
-
environment: 'node', // 'node' or 'jsdom' depending on your project
|
|
9
|
-
// setupFiles: ['./vitest.setup.ts'], // optional setup file
|
|
10
|
-
exclude: ['src/bin', 'node_modules', 'dist'], // exclude specific test paths
|
|
11
|
-
},
|
|
12
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|