@spscommerce/max 0.13.0 → 0.15.0

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/lib/utils.d.ts CHANGED
@@ -5,3 +5,5 @@ export declare const SETTINGS: {
5
5
  prod: string;
6
6
  };
7
7
  };
8
+ /** Total times the support FYI notice is shown before it stops for good. */
9
+ export declare const SUPPORT_FYI_MAX_VIEWS = 3;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spscommerce/max",
3
3
  "description": "",
4
- "version": "0.13.0",
4
+ "version": "0.15.0",
5
5
  "author": "SPS Commerce",
6
6
  "license": "UNLICENSED",
7
7
  "repository": "https://github.com/SPSCommerce/sps-agent-ui",
@@ -95,8 +95,9 @@
95
95
  "build:types": "tsc --emitDeclarationOnly --declaration --declarationDir lib",
96
96
  "watch": "vite build --watch",
97
97
  "test": "vitest",
98
- "test:ci": "vitest run",
98
+ "test:ci": "vitest run && node scripts/validate-locales.mjs",
99
99
  "lint": "eslint src --ext .ts,.tsx",
100
+ "lint:locales": "node scripts/validate-locales.mjs",
100
101
  "clean": "git clean -fdX",
101
102
  "pub": "node ../../../scripts/publish-package.mjs"
102
103
  }
@@ -0,0 +1,54 @@
1
+ import { readFileSync, readdirSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const localesDir = join(__dirname, "../src/locales");
7
+
8
+ const enUS = JSON.parse(readFileSync(join(localesDir, "en-US/max-translations.json"), "utf8"));
9
+ const enKeys = Object.keys(enUS);
10
+
11
+ const locales = readdirSync(localesDir, { withFileTypes: true })
12
+ .filter((d) => d.isDirectory() && d.name !== "en-US" && /^[a-z]{2}-[A-Z]{2}$/.test(d.name))
13
+ .map((d) => d.name);
14
+
15
+ let hasErrors = false;
16
+
17
+ for (const locale of locales) {
18
+ const filePath = join(localesDir, locale, "max-translations.json");
19
+ let translations;
20
+ try {
21
+ translations = JSON.parse(readFileSync(filePath, "utf8"));
22
+ } catch {
23
+ console.warn(`\n[WARN] ${locale}: could not parse file — skipping`);
24
+ continue;
25
+ }
26
+
27
+ const emptyKeys = Object.entries(translations)
28
+ .filter(([, v]) => v === "")
29
+ .map(([k]) => k);
30
+
31
+ const missingKeys = enKeys.filter((k) => !(k in translations));
32
+
33
+ if (emptyKeys.length > 0) {
34
+ hasErrors = true;
35
+ console.error(`\n[ERROR] ${locale}: ${emptyKeys.length} empty string(s):`);
36
+ emptyKeys.forEach((k) => console.error(` - ${k}`));
37
+ }
38
+
39
+ if (missingKeys.length > 0) {
40
+ console.warn(`\n[WARN] ${locale}: ${missingKeys.length} missing key(s) (will fall back to English):`);
41
+ missingKeys.forEach((k) => console.warn(` - ${k}`));
42
+ }
43
+
44
+ if (emptyKeys.length === 0 && missingKeys.length === 0) {
45
+ console.log(`[OK] ${locale}: all keys present and non-empty`);
46
+ }
47
+ }
48
+
49
+ if (hasErrors) {
50
+ console.error("\nLocale validation FAILED: fix empty string values before merging.");
51
+ process.exit(1);
52
+ }
53
+
54
+ console.log("\nLocale validation passed.");