@lingual/i18n-check 0.8.4 → 0.8.6
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/README.md +4 -4
- package/dist/bin/index.js +4 -1
- package/dist/index.js +2 -2
- package/dist/utils/nextIntlSrcParser.js +43 -0
- package/package.json +12 -11
- package/dist/bin/index.test.d.ts +0 -1
- package/dist/bin/index.test.js +0 -786
- package/dist/errorReporters.test.d.ts +0 -1
- package/dist/errorReporters.test.js +0 -165
- package/dist/utils/findInvalidTranslations.test.d.ts +0 -1
- package/dist/utils/findInvalidTranslations.test.js +0 -83
- package/dist/utils/findInvalidi18nTranslations.test.d.ts +0 -1
- package/dist/utils/findInvalidi18nTranslations.test.js +0 -206
- package/dist/utils/findMissingKeys.test.d.ts +0 -1
- package/dist/utils/findMissingKeys.test.js +0 -41
- package/dist/utils/flattenTranslations.test.d.ts +0 -1
- package/dist/utils/flattenTranslations.test.js +0 -28
- package/dist/utils/i18NextParser.test.d.ts +0 -1
- package/dist/utils/i18NextParser.test.js +0 -150
- package/dist/utils/nextIntlSrcParser.test.d.ts +0 -1
- package/dist/utils/nextIntlSrcParser.test.js +0 -568
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
It compares the defined source language with all target translation files and finds inconsistencies between source and target files.
|
|
5
5
|
You can run these checks as a pre-commit hook or on the CI depending on your use-case and setup.
|
|
6
6
|
|
|
7
|
-

|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
## Table of Contents
|
|
12
12
|
|
|
@@ -106,7 +106,7 @@ Additionally the `i18next` format is supported and can be set via the `-f` or `-
|
|
|
106
106
|
|
|
107
107
|
There are i18n libraries that have their own specific format, which might not be based on ICU and therefore can not be validated against currently. On a side-note: there might be future support for more specific formats.
|
|
108
108
|
|
|
109
|
-
Hint: If you want to use the `--unused` flag, you should provide `react-intl` or `i18-next` as the format. Also see the [`unused` section](#--unused) for more details.
|
|
109
|
+
Hint: If you want to use the `--unused` flag, you should provide `react-intl` or `i18-next` as the format. Also see the [`unused` section](#--unused--u) for more details.
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
112
|
yarn i18n:check --locales translations/i18NextMessageExamples -s en-US -f i18next
|
|
@@ -165,7 +165,7 @@ This feature is currently only supported for `react-intl` and `i18next` as well
|
|
|
165
165
|
|
|
166
166
|
Via the `-u` or `--unused` option you provide a source path to the code, which will be parsed to find all unused as well as undefined keys in the primary target language.
|
|
167
167
|
|
|
168
|
-
It is important to note that you must also provide the `-f` or `--format` option with `react-intl`, `i18next` or `next-intl` as value. See the [`format` section](#--format) for more information.
|
|
168
|
+
It is important to note that you must also provide the `-f` or `--format` option with `react-intl`, `i18next` or `next-intl` as value. See the [`format` section](#--format--f) for more information.
|
|
169
169
|
|
|
170
170
|
```bash
|
|
171
171
|
yarn i18n:check --locales translations/messageExamples -s en-US -u client/ -f react-intl
|
package/dist/bin/index.js
CHANGED
|
@@ -160,6 +160,7 @@ const main = async () => {
|
|
|
160
160
|
}
|
|
161
161
|
try {
|
|
162
162
|
const result = (0, __1.checkTranslations)(srcFiles, targetFiles, options);
|
|
163
|
+
let undefinedKeyResult = undefined;
|
|
163
164
|
printTranslationResult(result);
|
|
164
165
|
if (unusedSrcPath) {
|
|
165
166
|
const isMultiUnusedFolders = unusedSrcPath.length > 1;
|
|
@@ -176,11 +177,13 @@ const main = async () => {
|
|
|
176
177
|
printUndefinedKeysResult({
|
|
177
178
|
undefinedKeys,
|
|
178
179
|
});
|
|
180
|
+
undefinedKeyResult = undefinedKeys;
|
|
179
181
|
}
|
|
180
182
|
const end = performance.now();
|
|
181
183
|
console.log(chalk_1.default.green(`\nDone in ${Math.round(((end - start) * 100) / 1000) / 100}s.`));
|
|
182
184
|
if ((result.missingKeys && Object.keys(result.missingKeys).length > 0) ||
|
|
183
|
-
(result.invalidKeys && Object.keys(result.invalidKeys).length > 0)
|
|
185
|
+
(result.invalidKeys && Object.keys(result.invalidKeys).length > 0) ||
|
|
186
|
+
(undefinedKeyResult && Object.keys(undefinedKeyResult).length > 0)) {
|
|
184
187
|
(0, node_process_1.exit)(1);
|
|
185
188
|
}
|
|
186
189
|
else {
|
package/dist/index.js
CHANGED
|
@@ -32,12 +32,12 @@ const checkTranslations = (source, targets, options = { format: 'icu', checks: [
|
|
|
32
32
|
const files = Object.fromEntries(targets
|
|
33
33
|
.filter(({ reference }) => reference === name)
|
|
34
34
|
.map(({ name, content }) => [name, content]));
|
|
35
|
+
const filteredContent = filterKeys(content, options.ignore ?? []);
|
|
35
36
|
if (hasMissingKeysCheck) {
|
|
36
|
-
const filteredContent = filterKeys(content, options.ignore ?? []);
|
|
37
37
|
merge(missingKeys, (0, exports.checkMissingTranslations)(filteredContent, files));
|
|
38
38
|
}
|
|
39
39
|
if (hasInvalidKeysCheck) {
|
|
40
|
-
merge(invalidKeys, (0, exports.checkInvalidTranslations)(
|
|
40
|
+
merge(invalidKeys, (0, exports.checkInvalidTranslations)(filteredContent, files, options));
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
return {
|
|
@@ -140,6 +140,49 @@ const getKeys = (path) => {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
+
// Check if getTranslations is called inside a promise.all
|
|
144
|
+
// Example:
|
|
145
|
+
// const [data, t] = await Promise.all([
|
|
146
|
+
// loadData(id),
|
|
147
|
+
// getTranslations('asyncPromiseAll'),
|
|
148
|
+
// ]);
|
|
149
|
+
if (ts.isCallExpression(node.initializer.expression) &&
|
|
150
|
+
node.initializer.expression.arguments.length > 0 &&
|
|
151
|
+
ts.isArrayLiteralExpression(node.initializer.expression.arguments[0])) {
|
|
152
|
+
const functionNameIndex = node.initializer.expression.arguments[0].elements.findIndex((argument) => {
|
|
153
|
+
return (ts.isCallExpression(argument) &&
|
|
154
|
+
ts.isIdentifier(argument.expression) &&
|
|
155
|
+
argument.expression.text === GET_TRANSLATIONS);
|
|
156
|
+
});
|
|
157
|
+
// Try to find the correct function name via the position in the variable declaration
|
|
158
|
+
if (functionNameIndex !== -1 &&
|
|
159
|
+
ts.isArrayBindingPattern(node.name) &&
|
|
160
|
+
ts.isBindingElement(node.name.elements[functionNameIndex]) &&
|
|
161
|
+
ts.isIdentifier(node.name.elements[functionNameIndex].name)) {
|
|
162
|
+
const variable = node.name.elements[functionNameIndex].name.text;
|
|
163
|
+
const [argument] = ts.isCallExpression(node.initializer.expression.arguments[0].elements[functionNameIndex])
|
|
164
|
+
? node.initializer.expression.arguments[0].elements[functionNameIndex].arguments
|
|
165
|
+
: [];
|
|
166
|
+
if (argument && ts.isObjectLiteralExpression(argument)) {
|
|
167
|
+
argument.properties.forEach((property) => {
|
|
168
|
+
if (property &&
|
|
169
|
+
ts.isPropertyAssignment(property) &&
|
|
170
|
+
property.name &&
|
|
171
|
+
ts.isIdentifier(property.name) &&
|
|
172
|
+
property.name.text === 'namespace' &&
|
|
173
|
+
ts.isStringLiteral(property.initializer)) {
|
|
174
|
+
pushNamespace({ name: property.initializer.text, variable });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
else if (argument && ts.isStringLiteral(argument)) {
|
|
179
|
+
pushNamespace({ name: argument.text, variable });
|
|
180
|
+
}
|
|
181
|
+
else if (argument === undefined) {
|
|
182
|
+
pushNamespace({ name: '', variable });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
143
186
|
}
|
|
144
187
|
}
|
|
145
188
|
// Search for direct inline calls and extract namespace and key
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingual/i18n-check",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "i18n translation messages check",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"types": "dist/index.d.ts",
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsc",
|
|
13
|
+
"build": "tsc -p tsconfig.production.json",
|
|
14
14
|
"format": "prettier --write .",
|
|
15
15
|
"lint": "eslint src",
|
|
16
16
|
"lint:fix": "eslint src --fix ",
|
|
@@ -19,31 +19,32 @@
|
|
|
19
19
|
"test:cli": "tsc && jest src/bin/index.test.ts"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
|
-
"dist/"
|
|
22
|
+
"dist/",
|
|
23
|
+
"!dist/**/*.test.*"
|
|
23
24
|
],
|
|
24
25
|
"dependencies": {
|
|
25
26
|
"@formatjs/cli-lib": "^6.6.6",
|
|
26
27
|
"@formatjs/icu-messageformat-parser": "^2.11.2",
|
|
27
28
|
"chalk": "^4.1.2",
|
|
28
29
|
"commander": "^12.1.0",
|
|
29
|
-
"glob": "
|
|
30
|
+
"glob": "11.0.2",
|
|
30
31
|
"i18next-parser": "^9.3.0",
|
|
31
32
|
"js-yaml": "^4.1.0",
|
|
32
33
|
"typescript": "^5.8.3"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
|
-
"@eslint/js": "^9.
|
|
36
|
+
"@eslint/js": "^9.30.1",
|
|
36
37
|
"@types/jest": "^29.5.14",
|
|
37
38
|
"@types/js-yaml": "^4.0.9",
|
|
38
|
-
"@types/node": "^22.
|
|
39
|
+
"@types/node": "^22.16.0",
|
|
39
40
|
"@types/vinyl": "^2.0.12",
|
|
40
41
|
"braces": "^3.0.3",
|
|
41
|
-
"eslint": "^9.
|
|
42
|
-
"globals": "^16.
|
|
42
|
+
"eslint": "^9.30.1",
|
|
43
|
+
"globals": "^16.3.0",
|
|
43
44
|
"jest": "^29.7.0",
|
|
44
|
-
"prettier": "^3.
|
|
45
|
-
"ts-jest": "^29.
|
|
46
|
-
"typescript-eslint": "^8.
|
|
45
|
+
"prettier": "^3.6.2",
|
|
46
|
+
"ts-jest": "^29.4.0",
|
|
47
|
+
"typescript-eslint": "^8.35.1"
|
|
47
48
|
},
|
|
48
49
|
"repository": {
|
|
49
50
|
"type": "git",
|
package/dist/bin/index.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|