@formatjs/cli-lib 8.0.8 → 8.1.1
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/index.d.ts +7 -7
- package/index.js +2 -2
- package/main.d.ts +0 -1
- package/main.js +1 -1
- package/package.json +5 -5
- package/src/cli.js +99 -153
- package/src/compile.d.ts +45 -45
- package/src/compile.js +79 -80
- package/src/compile_folder.d.ts +1 -1
- package/src/compile_folder.js +6 -6
- package/src/console_utils.d.ts +3 -1
- package/src/console_utils.js +44 -46
- package/src/extract.d.ts +68 -68
- package/src/extract.js +165 -182
- package/src/formatters/crowdin.d.ts +3 -3
- package/src/formatters/crowdin.js +19 -20
- package/src/formatters/default.d.ts +1 -1
- package/src/formatters/default.js +8 -7
- package/src/formatters/index.d.ts +6 -6
- package/src/formatters/index.js +29 -34
- package/src/formatters/lokalise.d.ts +5 -5
- package/src/formatters/lokalise.js +16 -17
- package/src/formatters/simple.d.ts +1 -1
- package/src/formatters/simple.js +7 -6
- package/src/formatters/smartling.d.ts +13 -15
- package/src/formatters/smartling.js +35 -40
- package/src/formatters/transifex.d.ts +5 -5
- package/src/formatters/transifex.js +16 -17
- package/src/gts_extractor.js +11 -11
- package/src/hbs_extractor.js +34 -41
- package/src/parse_script.d.ts +5 -5
- package/src/parse_script.js +40 -43
- package/src/pseudo_locale.d.ts +15 -15
- package/src/pseudo_locale.js +210 -94
- package/src/verify/checkExtraKeys.js +28 -32
- package/src/verify/checkMissingKeys.js +29 -33
- package/src/verify/checkStructuralEquality.js +67 -71
- package/src/verify/index.d.ts +5 -5
- package/src/verify/index.js +24 -27
- package/src/vue_extractor.js +52 -62
package/src/pseudo_locale.js
CHANGED
|
@@ -1,115 +1,231 @@
|
|
|
1
|
-
import { parse, TYPE, isLiteralElement, isPluralElement, isSelectElement, isTagElement
|
|
1
|
+
import { parse, TYPE, isLiteralElement, isPluralElement, isSelectElement, isTagElement } from "@formatjs/icu-messageformat-parser";
|
|
2
2
|
function forEachLiteralElement(ast, fn) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
});
|
|
3
|
+
ast.forEach((el) => {
|
|
4
|
+
if (isLiteralElement(el)) {
|
|
5
|
+
fn(el);
|
|
6
|
+
} else if (isPluralElement(el) || isSelectElement(el)) {
|
|
7
|
+
for (const opt of Object.values(el.options)) {
|
|
8
|
+
forEachLiteralElement(opt.value, fn);
|
|
9
|
+
}
|
|
10
|
+
} else if (isTagElement(el)) {
|
|
11
|
+
forEachLiteralElement(el.children, fn);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
16
14
|
}
|
|
17
15
|
export function generateXXLS(msg) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
const ast = typeof msg === "string" ? parse(msg) : msg;
|
|
17
|
+
const lastChunk = ast[ast.length - 1];
|
|
18
|
+
if (lastChunk && isLiteralElement(lastChunk)) {
|
|
19
|
+
lastChunk.value += "SSSSSSSSSSSSSSSSSSSSSSSSS";
|
|
20
|
+
return ast;
|
|
21
|
+
}
|
|
22
|
+
return [...ast, {
|
|
23
|
+
type: TYPE.literal,
|
|
24
|
+
value: "SSSSSSSSSSSSSSSSSSSSSSSSS"
|
|
25
|
+
}];
|
|
25
26
|
}
|
|
26
27
|
export function generateXXAC(msg) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const ast = typeof msg === "string" ? parse(msg) : msg;
|
|
29
|
+
forEachLiteralElement(ast, (el) => {
|
|
30
|
+
el.value = el.value.toUpperCase();
|
|
31
|
+
});
|
|
32
|
+
return ast;
|
|
32
33
|
}
|
|
33
34
|
export function generateXXHA(msg) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
const ast = typeof msg === "string" ? parse(msg) : msg;
|
|
36
|
+
const [firstChunk, ...rest] = ast;
|
|
37
|
+
if (firstChunk && isLiteralElement(firstChunk)) {
|
|
38
|
+
firstChunk.value = "[javascript]" + firstChunk.value;
|
|
39
|
+
return [firstChunk, ...rest];
|
|
40
|
+
}
|
|
41
|
+
return [{
|
|
42
|
+
type: TYPE.literal,
|
|
43
|
+
value: "[javascript]"
|
|
44
|
+
}, ...ast];
|
|
41
45
|
}
|
|
42
46
|
const ACCENTED_MAP = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
"caps": [
|
|
48
|
+
550,
|
|
49
|
+
385,
|
|
50
|
+
391,
|
|
51
|
+
7698,
|
|
52
|
+
7702,
|
|
53
|
+
401,
|
|
54
|
+
403,
|
|
55
|
+
294,
|
|
56
|
+
298,
|
|
57
|
+
308,
|
|
58
|
+
310,
|
|
59
|
+
319,
|
|
60
|
+
7742,
|
|
61
|
+
544,
|
|
62
|
+
510,
|
|
63
|
+
420,
|
|
64
|
+
586,
|
|
65
|
+
344,
|
|
66
|
+
350,
|
|
67
|
+
358,
|
|
68
|
+
364,
|
|
69
|
+
7804,
|
|
70
|
+
7814,
|
|
71
|
+
7818,
|
|
72
|
+
7822,
|
|
73
|
+
7824
|
|
74
|
+
],
|
|
75
|
+
"small": [
|
|
76
|
+
551,
|
|
77
|
+
384,
|
|
78
|
+
392,
|
|
79
|
+
7699,
|
|
80
|
+
7703,
|
|
81
|
+
402,
|
|
82
|
+
608,
|
|
83
|
+
295,
|
|
84
|
+
299,
|
|
85
|
+
309,
|
|
86
|
+
311,
|
|
87
|
+
320,
|
|
88
|
+
7743,
|
|
89
|
+
414,
|
|
90
|
+
511,
|
|
91
|
+
421,
|
|
92
|
+
587,
|
|
93
|
+
345,
|
|
94
|
+
351,
|
|
95
|
+
359,
|
|
96
|
+
365,
|
|
97
|
+
7805,
|
|
98
|
+
7815,
|
|
99
|
+
7819,
|
|
100
|
+
7823,
|
|
101
|
+
7825
|
|
102
|
+
]
|
|
49
103
|
};
|
|
50
104
|
const FLIPPED_MAP = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
105
|
+
"caps": [
|
|
106
|
+
8704,
|
|
107
|
+
1296,
|
|
108
|
+
8579,
|
|
109
|
+
5601,
|
|
110
|
+
398,
|
|
111
|
+
8498,
|
|
112
|
+
8513,
|
|
113
|
+
72,
|
|
114
|
+
73,
|
|
115
|
+
383,
|
|
116
|
+
1276,
|
|
117
|
+
8514,
|
|
118
|
+
87,
|
|
119
|
+
78,
|
|
120
|
+
79,
|
|
121
|
+
1280,
|
|
122
|
+
210,
|
|
123
|
+
7450,
|
|
124
|
+
83,
|
|
125
|
+
8869,
|
|
126
|
+
8745,
|
|
127
|
+
581,
|
|
128
|
+
77,
|
|
129
|
+
88,
|
|
130
|
+
8516,
|
|
131
|
+
90
|
|
132
|
+
],
|
|
133
|
+
"small": [
|
|
134
|
+
592,
|
|
135
|
+
113,
|
|
136
|
+
596,
|
|
137
|
+
112,
|
|
138
|
+
477,
|
|
139
|
+
607,
|
|
140
|
+
387,
|
|
141
|
+
613,
|
|
142
|
+
305,
|
|
143
|
+
638,
|
|
144
|
+
670,
|
|
145
|
+
645,
|
|
146
|
+
623,
|
|
147
|
+
117,
|
|
148
|
+
111,
|
|
149
|
+
100,
|
|
150
|
+
98,
|
|
151
|
+
633,
|
|
152
|
+
115,
|
|
153
|
+
647,
|
|
154
|
+
110,
|
|
155
|
+
652,
|
|
156
|
+
653,
|
|
157
|
+
120,
|
|
158
|
+
654,
|
|
159
|
+
122
|
|
160
|
+
]
|
|
57
161
|
};
|
|
58
162
|
/**
|
|
59
|
-
|
|
60
|
-
|
|
163
|
+
* Based on: https://hg.mozilla.org/mozilla-central/file/a1f74e8c8fb72390d22054d6b00c28b1a32f6c43/intl/l10n/L10nRegistry.jsm#l425
|
|
164
|
+
*/
|
|
61
165
|
function transformString(map, elongate = false, msg) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
166
|
+
return msg.replace(/[a-z]/gi, (ch) => {
|
|
167
|
+
const cc = ch.charCodeAt(0);
|
|
168
|
+
if (cc >= 97 && cc <= 122) {
|
|
169
|
+
const newChar = String.fromCodePoint(map.small[cc - 97]);
|
|
170
|
+
// duplicate "a", "e", "o" and "u" to emulate ~30% longer text
|
|
171
|
+
if (elongate && (cc === 97 || cc === 101 || cc === 111 || cc === 117)) {
|
|
172
|
+
return newChar + newChar;
|
|
173
|
+
}
|
|
174
|
+
return newChar;
|
|
175
|
+
}
|
|
176
|
+
if (cc >= 65 && cc <= 90) {
|
|
177
|
+
return String.fromCodePoint(map.caps[cc - 65]);
|
|
178
|
+
}
|
|
179
|
+
return ch;
|
|
180
|
+
});
|
|
77
181
|
}
|
|
78
182
|
/**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
183
|
+
* accented - Ȧȧƈƈḗḗƞŧḗḗḓ Ḗḗƞɠŀīīşħ
|
|
184
|
+
* --------------------------------
|
|
185
|
+
*
|
|
186
|
+
* This locale replaces all Latin characters with their accented equivalents, and duplicates some
|
|
187
|
+
* vowels to create roughly 30% longer strings. Strings are wrapped in markers (square brackets),
|
|
188
|
+
* which help with detecting truncation.
|
|
189
|
+
*/
|
|
86
190
|
export function generateENXA(msg) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
191
|
+
const ast = typeof msg === "string" ? parse(msg) : msg;
|
|
192
|
+
forEachLiteralElement(ast, (el) => {
|
|
193
|
+
el.value = transformString(ACCENTED_MAP, true, el.value);
|
|
194
|
+
});
|
|
195
|
+
return [
|
|
196
|
+
{
|
|
197
|
+
type: TYPE.literal,
|
|
198
|
+
value: "["
|
|
199
|
+
},
|
|
200
|
+
...ast,
|
|
201
|
+
{
|
|
202
|
+
type: TYPE.literal,
|
|
203
|
+
value: "]"
|
|
204
|
+
}
|
|
205
|
+
];
|
|
96
206
|
}
|
|
97
207
|
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
208
|
+
* bidi - ɥsıʅƃuƎ ıpıԐ
|
|
209
|
+
* -------------------
|
|
210
|
+
*
|
|
211
|
+
* This strategy replaces all Latin characters with their 180 degree rotated versions and enforces
|
|
212
|
+
* right to left text flow using Unicode UAX#9 Explicit Directional Embeddings. In this mode, the UI
|
|
213
|
+
* directionality will also be set to right-to-left.
|
|
214
|
+
*/
|
|
105
215
|
export function generateENXB(msg) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
216
|
+
const ast = typeof msg === "string" ? parse(msg) : msg;
|
|
217
|
+
forEachLiteralElement(ast, (el) => {
|
|
218
|
+
el.value = transformString(FLIPPED_MAP, false, el.value);
|
|
219
|
+
});
|
|
220
|
+
return [
|
|
221
|
+
{
|
|
222
|
+
type: TYPE.literal,
|
|
223
|
+
value: ""
|
|
224
|
+
},
|
|
225
|
+
...ast,
|
|
226
|
+
{
|
|
227
|
+
type: TYPE.literal,
|
|
228
|
+
value: ""
|
|
229
|
+
}
|
|
230
|
+
];
|
|
115
231
|
}
|
|
@@ -1,36 +1,32 @@
|
|
|
1
|
-
import { debug, writeStderr } from
|
|
1
|
+
import { debug, writeStderr } from "../console_utils.js";
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function extractKeys(obj, parentKey =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.map(k => [parentKey ? `${parentKey}.${k}` : k, ...extractKeys(obj[k], k)])
|
|
14
|
-
.flat();
|
|
3
|
+
* Flatten nested obj into list of keys, delimited by `.`
|
|
4
|
+
* @param obj
|
|
5
|
+
* @param parentKey
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
function extractKeys(obj, parentKey = "") {
|
|
9
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return Object.keys(obj).map((k) => [parentKey ? `${parentKey}.${k}` : k, ...extractKeys(obj[k], k)]).flat();
|
|
15
13
|
}
|
|
16
14
|
export async function checkExtraKeys(translationFilesContents, sourceLocale) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return false;
|
|
35
|
-
}, true);
|
|
15
|
+
debug("Checking translation files:");
|
|
16
|
+
const sourceContent = translationFilesContents[sourceLocale];
|
|
17
|
+
if (!sourceContent) {
|
|
18
|
+
throw new Error(`Missing source ${sourceLocale}.json file`);
|
|
19
|
+
}
|
|
20
|
+
const sourceKeys = extractKeys(sourceContent);
|
|
21
|
+
return Object.entries(translationFilesContents).filter(([locale]) => locale !== sourceLocale).reduce((result, [locale, content]) => {
|
|
22
|
+
const localeKeys = new Set(extractKeys(content));
|
|
23
|
+
const extraKeys = new Set(Array.from(localeKeys).filter((k) => !sourceKeys.includes(k)));
|
|
24
|
+
if (!extraKeys.size) {
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
writeStderr("---------------------------------\n");
|
|
28
|
+
writeStderr(`Extra translation keys for locale ${locale}:\n`);
|
|
29
|
+
extraKeys.forEach((r) => writeStderr(`${r}\n`));
|
|
30
|
+
return false;
|
|
31
|
+
}, true);
|
|
36
32
|
}
|
|
@@ -1,37 +1,33 @@
|
|
|
1
|
-
import { debug, writeStderr } from
|
|
1
|
+
import { debug, writeStderr } from "../console_utils.js";
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function extractKeys(obj, parentKey =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.map(k => [parentKey ? `${parentKey}.${k}` : k, ...extractKeys(obj[k], k)])
|
|
14
|
-
.flat();
|
|
3
|
+
* Flatten nested obj into list of keys, delimited by `.`
|
|
4
|
+
* @param obj
|
|
5
|
+
* @param parentKey
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
function extractKeys(obj, parentKey = "") {
|
|
9
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return Object.keys(obj).map((k) => [parentKey ? `${parentKey}.${k}` : k, ...extractKeys(obj[k], k)]).flat();
|
|
15
13
|
}
|
|
16
14
|
export async function checkMissingKeys(translationFilesContents, sourceLocale) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return false;
|
|
36
|
-
}, true);
|
|
15
|
+
debug("Checking translation files:");
|
|
16
|
+
const sourceContent = translationFilesContents[sourceLocale];
|
|
17
|
+
if (!sourceContent) {
|
|
18
|
+
throw new Error(`Missing source ${sourceLocale}.json file`);
|
|
19
|
+
}
|
|
20
|
+
const sourceKeys = extractKeys(sourceContent);
|
|
21
|
+
return Object.entries(translationFilesContents).filter(([locale]) => locale !== sourceLocale).reduce((result, [locale, content]) => {
|
|
22
|
+
const localeKeys = new Set(extractKeys(content));
|
|
23
|
+
const missingKeys = new Set(sourceKeys.filter((r) => !localeKeys.has(r)));
|
|
24
|
+
// We're being lenient here since only missing keys are currently considered breaking
|
|
25
|
+
if (!missingKeys.size) {
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
writeStderr("---------------------------------\n");
|
|
29
|
+
writeStderr(`Missing translation keys for locale ${locale}:\n`);
|
|
30
|
+
missingKeys.forEach((r) => writeStderr(`${r}\n`));
|
|
31
|
+
return false;
|
|
32
|
+
}, true);
|
|
37
33
|
}
|
|
@@ -1,75 +1,71 @@
|
|
|
1
|
-
import { isStructurallySame, parse
|
|
2
|
-
import { debug, writeStderr } from
|
|
3
|
-
import { error } from
|
|
1
|
+
import { isStructurallySame, parse } from "@formatjs/icu-messageformat-parser";
|
|
2
|
+
import { debug, writeStderr } from "../console_utils.js";
|
|
3
|
+
import { error } from "console";
|
|
4
4
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function flatten(obj, parentKey =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}, {});
|
|
5
|
+
* Flatten nested obj into list of keys, delimited by `.`
|
|
6
|
+
* @param obj
|
|
7
|
+
* @param parentKey
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
function flatten(obj, parentKey = "") {
|
|
11
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
return Object.keys(obj).reduce((all, k) => {
|
|
15
|
+
const value = obj[k];
|
|
16
|
+
const key = parentKey ? `${parentKey}.${k}` : k;
|
|
17
|
+
if (typeof value === "object") {
|
|
18
|
+
Object.assign(all, flatten(value, key));
|
|
19
|
+
} else {
|
|
20
|
+
all[key] = value;
|
|
21
|
+
}
|
|
22
|
+
return all;
|
|
23
|
+
}, {});
|
|
25
24
|
}
|
|
26
25
|
export async function checkStructuralEquality(translationFilesContents, sourceLocale) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
problematicKeys.forEach(({ key, error }) => writeStderr(`${key}: ${error?.message}\n`));
|
|
73
|
-
return false;
|
|
74
|
-
}, true);
|
|
26
|
+
debug("Checking translation files:");
|
|
27
|
+
const sourceContent = translationFilesContents[sourceLocale];
|
|
28
|
+
if (!sourceContent) {
|
|
29
|
+
throw new Error(`Missing source ${sourceLocale}.json file`);
|
|
30
|
+
}
|
|
31
|
+
const sourceMessages = Object.entries(flatten(sourceContent)).reduce((all, [key, value]) => {
|
|
32
|
+
try {
|
|
33
|
+
all[key] = parse(value);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
error("Error parsing message", key, value, e);
|
|
36
|
+
}
|
|
37
|
+
return all;
|
|
38
|
+
}, {});
|
|
39
|
+
return Object.entries(translationFilesContents).filter(([locale]) => locale !== sourceLocale).reduce((result, [locale, content]) => {
|
|
40
|
+
const localeMessages = flatten(content);
|
|
41
|
+
const problematicKeys = Object.keys(sourceMessages).map((k) => {
|
|
42
|
+
if (!localeMessages[k]) {
|
|
43
|
+
return {
|
|
44
|
+
key: k,
|
|
45
|
+
success: true
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const sourceMessage = sourceMessages[k];
|
|
49
|
+
try {
|
|
50
|
+
const localeMessage = parse(localeMessages[k]);
|
|
51
|
+
return {
|
|
52
|
+
key: k,
|
|
53
|
+
...isStructurallySame(sourceMessage, localeMessage)
|
|
54
|
+
};
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return {
|
|
57
|
+
key: k,
|
|
58
|
+
success: false,
|
|
59
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}).filter((s) => !s.success);
|
|
63
|
+
if (!problematicKeys.length) {
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
writeStderr("---------------------------------\n");
|
|
67
|
+
writeStderr(`These translation keys for locale ${locale} are structurally different from ${sourceLocale}:\n`);
|
|
68
|
+
problematicKeys.forEach(({ key, error }) => writeStderr(`${key}: ${error?.message}\n`));
|
|
69
|
+
return false;
|
|
70
|
+
}, true);
|
|
75
71
|
}
|
package/src/verify/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export interface VerifyOpts {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
sourceLocale: string;
|
|
3
|
+
missingKeys: boolean;
|
|
4
|
+
extraKeys: boolean;
|
|
5
|
+
structuralEquality: boolean;
|
|
6
|
+
ignore?: string[];
|
|
7
7
|
}
|
|
8
8
|
export declare function verify(files: string[], { sourceLocale, missingKeys, extraKeys, structuralEquality }: VerifyOpts): Promise<void>;
|