@lingual/i18n-check 0.7.1 → 0.7.3

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 CHANGED
@@ -60,7 +60,7 @@ const main = async () => {
60
60
  const localePathFolders = localePath;
61
61
  const isMultiFolders = localePathFolders.length > 1;
62
62
  let srcFiles = [];
63
- let localeFiles = [];
63
+ let targetFiles = [];
64
64
  const pattern = isMultiFolders
65
65
  ? `{${localePath.join(",").trim()}}/**/*.{json,yaml,yml}`
66
66
  : `${localePath.join(",").trim()}/**/*.{json,yaml,yml}`;
@@ -135,7 +135,7 @@ const main = async () => {
135
135
  return false;
136
136
  });
137
137
  if (reference) {
138
- localeFiles.push({
138
+ targetFiles.push({
139
139
  reference: reference.file,
140
140
  name: file,
141
141
  content,
@@ -147,12 +147,14 @@ const main = async () => {
147
147
  console.log(chalk_1.default.red("Source not found. Please provide a valid source locale, i.e. -s en-US"));
148
148
  (0, node_process_1.exit)(1);
149
149
  }
150
- if (localeFiles.length === 0) {
150
+ if ((options.checks.includes("missingKeys") ||
151
+ options.checks.includes("invalidKeys")) &&
152
+ targetFiles.length === 0) {
151
153
  console.log(chalk_1.default.red("Locale file(s) not found. Please provide valid locale file(s), i.e. --locales translations/"));
152
154
  (0, node_process_1.exit)(1);
153
155
  }
154
156
  try {
155
- const result = (0, __1.checkTranslations)(srcFiles, localeFiles, options);
157
+ const result = (0, __1.checkTranslations)(srcFiles, targetFiles, options);
156
158
  printTranslationResult(result);
157
159
  if (unusedSrcPath) {
158
160
  const filesToParse = (0, glob_1.globSync)(`${unusedSrcPath}/**/*.{ts,tsx}`, {
@@ -344,11 +344,21 @@ Found unused keys!
344
344
  └───────────────────────────────────────────────────────────────────┴──────────────────┘
345
345
 
346
346
  Found undefined keys!
347
- ┌─────────────────────────────────────────────────────┬──────────────────┐
348
- │ file │ key
349
- ├─────────────────────────────────────────────────────┼──────────────────┤
350
- │ translations/codeExamples/next-intl/src/Basic.tsx │ message.select
351
- └─────────────────────────────────────────────────────┴──────────────────┘
347
+ ┌──────────────────────────────────────────────────────────────────┬───────────────────┐
348
+ │ file │ key
349
+ ├──────────────────────────────────────────────────────────────────┼───────────────────┤
350
+ │ translations/codeExamples/next-intl/src/Basic.tsx │ message.select
351
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ unknown.unknown │
352
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ About.unknown │
353
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ unknown │
354
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ Test.title │
355
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ title │
356
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ unknown.unknown │
357
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ About.unknown │
358
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ unknown │
359
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ Test.title │
360
+ │ translations/codeExamples/next-intl/src/StrictTypesExample.tsx │ title │
361
+ └──────────────────────────────────────────────────────────────────┴───────────────────┘
352
362
 
353
363
  `);
354
364
  done();
@@ -134,6 +134,48 @@ const getKeys = (path) => {
134
134
  }
135
135
  }
136
136
  }
137
+ // Search for direct inline calls and extract namespace and key
138
+ //
139
+ // useTranslations("ns1")("one")
140
+ // useTranslations("ns1").rich("one");
141
+ // useTranslations("ns1").raw("one");
142
+ if (ts.isExpressionStatement(node)) {
143
+ let inlineNamespace = null;
144
+ if (node.expression && ts.isCallExpression(node.expression)) {
145
+ // Search: useTranslations("ns1")("one")
146
+ if (ts.isCallExpression(node.expression.expression) &&
147
+ ts.isIdentifier(node.expression.expression.expression)) {
148
+ if (node.expression.expression.expression.text === USE_TRANSLATIONS) {
149
+ const [argument] = node.expression.expression.arguments;
150
+ if (argument && ts.isStringLiteral(argument)) {
151
+ inlineNamespace = argument.text;
152
+ }
153
+ }
154
+ }
155
+ // Search: useTranslations("ns1").*("one")
156
+ if (ts.isPropertyAccessExpression(node.expression.expression) &&
157
+ ts.isCallExpression(node.expression.expression.expression) &&
158
+ ts.isIdentifier(node.expression.expression.expression.expression)) {
159
+ if (node.expression.expression.expression.expression.text ===
160
+ USE_TRANSLATIONS) {
161
+ const [argument] = node.expression.expression.expression.arguments;
162
+ if (argument && ts.isStringLiteral(argument)) {
163
+ inlineNamespace = argument.text;
164
+ }
165
+ }
166
+ const [callArgument] = node.expression.arguments;
167
+ if (callArgument && ts.isStringLiteral(callArgument)) {
168
+ const key = callArgument.text;
169
+ if (key) {
170
+ foundKeys.push({
171
+ key: inlineNamespace ? `${inlineNamespace}.${key}` : key,
172
+ meta: { file: path },
173
+ });
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
137
179
  // Search for `t()` calls
138
180
  if (getCurrentNamespace() !== null &&
139
181
  ts.isCallExpression(node) &&
@@ -12,6 +12,7 @@ const clientCounterFile = node_path_1.default.join(srcPath, "ClientCounter.tsx")
12
12
  const nestedExampleFile = node_path_1.default.join(srcPath, "NestedExample.tsx");
13
13
  const asyncExampleFile = node_path_1.default.join(srcPath, "AsyncExample.tsx");
14
14
  const dynamicKeysExamplFile = node_path_1.default.join(srcPath, "DynamicKeysExample.tsx");
15
+ const strictTypesExample = node_path_1.default.join(srcPath, "StrictTypesExample.tsx");
15
16
  describe("nextIntlSrcParser", () => {
16
17
  it("should find all the translation keys", () => {
17
18
  const keys = (0, nextIntlSrcParser_1.extract)([basicFile, counterFile, clientCounterFile]);
@@ -303,4 +304,177 @@ describe("nextIntlSrcParser", () => {
303
304
  },
304
305
  ]);
305
306
  });
307
+ it("should find all strict typed keys", () => {
308
+ const keys = (0, nextIntlSrcParser_1.extract)([strictTypesExample]);
309
+ expect(keys).toEqual([
310
+ {
311
+ key: "unknown.unknown",
312
+ meta: {
313
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
314
+ },
315
+ },
316
+ {
317
+ key: "About.unknown",
318
+ meta: {
319
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
320
+ },
321
+ },
322
+ {
323
+ key: "unknown",
324
+ meta: {
325
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
326
+ },
327
+ },
328
+ {
329
+ key: "Test.title",
330
+ meta: {
331
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
332
+ },
333
+ },
334
+ {
335
+ key: "title",
336
+ meta: {
337
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
338
+ },
339
+ },
340
+ {
341
+ key: "PageLayout.pageTitle",
342
+ meta: {
343
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
344
+ },
345
+ },
346
+ {
347
+ key: "NotFound.title",
348
+ meta: {
349
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
350
+ },
351
+ },
352
+ {
353
+ key: "Navigation.about",
354
+ meta: {
355
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
356
+ },
357
+ },
358
+ {
359
+ key: "About.title",
360
+ meta: {
361
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
362
+ },
363
+ },
364
+ {
365
+ key: "Navigation.about",
366
+ meta: {
367
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
368
+ },
369
+ },
370
+ {
371
+ key: "About.lastUpdated",
372
+ meta: {
373
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
374
+ },
375
+ },
376
+ {
377
+ key: "About.title",
378
+ meta: {
379
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
380
+ },
381
+ },
382
+ {
383
+ key: "StrictTypes.nested.another.level",
384
+ meta: {
385
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
386
+ },
387
+ },
388
+ {
389
+ key: "StrictTypes.nested.hello",
390
+ meta: {
391
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
392
+ },
393
+ },
394
+ {
395
+ key: "unknown.unknown",
396
+ meta: {
397
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
398
+ },
399
+ },
400
+ {
401
+ key: "About.unknown",
402
+ meta: {
403
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
404
+ },
405
+ },
406
+ {
407
+ key: "unknown",
408
+ meta: {
409
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
410
+ },
411
+ },
412
+ {
413
+ key: "Test.title",
414
+ meta: {
415
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
416
+ },
417
+ },
418
+ {
419
+ key: "title",
420
+ meta: {
421
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
422
+ },
423
+ },
424
+ {
425
+ key: "PageLayout.pageTitle",
426
+ meta: {
427
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
428
+ },
429
+ },
430
+ {
431
+ key: "NotFound.title",
432
+ meta: {
433
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
434
+ },
435
+ },
436
+ {
437
+ key: "Navigation.about",
438
+ meta: {
439
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
440
+ },
441
+ },
442
+ {
443
+ key: "About.title",
444
+ meta: {
445
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
446
+ },
447
+ },
448
+ {
449
+ key: "Navigation.about",
450
+ meta: {
451
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
452
+ },
453
+ },
454
+ {
455
+ key: "About.lastUpdated",
456
+ meta: {
457
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
458
+ },
459
+ },
460
+ {
461
+ key: "About.title",
462
+ meta: {
463
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
464
+ },
465
+ },
466
+ {
467
+ key: "StrictTypes.nested.another.level",
468
+ meta: {
469
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
470
+ },
471
+ },
472
+ {
473
+ key: "StrictTypes.nested.hello",
474
+ meta: {
475
+ file: "translations/codeExamples/next-intl/src/StrictTypesExample.tsx",
476
+ },
477
+ },
478
+ ]);
479
+ });
306
480
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingual/i18n-check",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "i18n translation messages check",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "@formatjs/cli-lib": "^6.6.6",
22
- "@formatjs/icu-messageformat-parser": "^2.11.0",
22
+ "@formatjs/icu-messageformat-parser": "^2.11.2",
23
23
  "chalk": "^4.1.2",
24
24
  "commander": "^12.1.0",
25
25
  "glob": "^11.0.1",
@@ -30,11 +30,11 @@
30
30
  "devDependencies": {
31
31
  "@types/jest": "^29.5.14",
32
32
  "@types/js-yaml": "^4.0.9",
33
- "@types/node": "^22.10.10",
33
+ "@types/node": "^22.14.1",
34
34
  "@types/vinyl": "^2.0.12",
35
35
  "braces": "^3.0.3",
36
36
  "jest": "^29.7.0",
37
- "ts-jest": "^29.2.6"
37
+ "ts-jest": "^29.3.2"
38
38
  },
39
39
  "repository": {
40
40
  "type": "git",