From d282813bc50badf796dc4f9ee5839638a0a285c5 Mon Sep 17 00:00:00 2001 From: John Coffey Date: Thu, 10 Sep 2026 14:21:42 -0700 Subject: [PATCH] Give the i18n scripts a parser again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TypeScript 7 is the native port: the package ships a `tsc` shim over a Go binary, and `typescript` now exports `version` and `versionMajorMinor` and no compiler API. Every `ts.createSourceFile` in scripts/ has been throwing "Cannot read properties of undefined (reading 'Latest')" since the 5.9.3 → 7.0.2 bump -- four of the five i18n scripts dead, only i18n-extract still running. Nothing noticed because no workflow runs them. The catalogue gate for nine languages has been dark, and the only signal was running it by hand. There is no official TS7 API package (@typescript/ast and @typescript/api are both 404), and the alternative was rewriting 493 lines and 25 distinct AST calls, including the JSX guards, against a different tree -- in tooling with no tests of its own. So `typescript-ast` is an npm alias for the last TypeScript carrying the JS API. It parses; `typescript` still type-checks and builds. Two entries, two jobs, said so in each script so the next reader does not delete one as a leftover. What the gate says now it can speak: catalogues are green and coverage is 100%. The "16 falling back to English" it reports in every locale are placeholders, example domains, a product name, a licence id and the quote glyph -- strings that should stay English. The 41 stale keys per locale are real dead weight and are left for their own change. --- package-lock.json | 18 +++++++++++++++++- package.json | 3 ++- scripts/i18n-catalog-check.mjs | 16 +++++++++++++++- scripts/i18n-coverage.mjs | 16 +++++++++++++++- scripts/i18n-extract.mjs | 16 +++++++++++++++- scripts/i18n-literals.mjs | 16 +++++++++++++++- scripts/i18n-strings.mjs | 16 +++++++++++++++- 7 files changed, 94 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 483f2e5..ab01127 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ ], "devDependencies": { "concurrently": "^9.1.2", - "typescript": "^7.0.2" + "typescript": "^7.0.2", + "typescript-ast": "npm:typescript@^5.9.3" }, "engines": { "node": ">=20.19" @@ -2777,6 +2778,21 @@ "@typescript/typescript-win32-x64": "7.0.2" } }, + "node_modules/typescript-ast": { + "name": "typescript", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "8.9.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", diff --git a/package.json b/package.json index 8717c74..d8b71b7 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "devDependencies": { "concurrently": "^9.1.2", - "typescript": "^7.0.2" + "typescript": "^7.0.2", + "typescript-ast": "npm:typescript@^5.9.3" } } diff --git a/scripts/i18n-catalog-check.mjs b/scripts/i18n-catalog-check.mjs index 289aa8d..7281af1 100644 --- a/scripts/i18n-catalog-check.mjs +++ b/scripts/i18n-catalog-check.mjs @@ -12,7 +12,21 @@ * in the file looking correct, is never looked up, and the app renders English * for ever. Nothing warns, because a catalogue is only ever read by key. */ -import ts from "typescript"; +/* + * The parser, not the compiler. + * + * TypeScript 7 is the native port: its package ships a `tsc` shim over a Go + * binary and nothing else, so `typescript` now exports `version` and + * `versionMajorMinor` and no compiler API at all. Every `ts.createSourceFile` + * in this directory started throwing "Cannot read properties of undefined + * (reading 'Latest')" the day the bump landed, and nothing noticed, because no + * workflow runs these. + * + * `typescript-ast` is an npm alias for the last TypeScript that carries the JS + * API (see package.json). It parses; `typescript` still type-checks and builds. + * Two entries, two jobs -- not a version someone forgot to remove. + */ +import ts from "typescript-ast"; import { readFileSync, globSync } from "node:fs"; const wanted = new Set(); diff --git a/scripts/i18n-coverage.mjs b/scripts/i18n-coverage.mjs index efd496d..024aa3c 100755 --- a/scripts/i18n-coverage.mjs +++ b/scripts/i18n-coverage.mjs @@ -11,7 +11,21 @@ * exits non-zero only with --check, so CI can be told to fail on regressions * later, once the number is low enough for that to mean something. */ -import ts from "typescript"; +/* + * The parser, not the compiler. + * + * TypeScript 7 is the native port: its package ships a `tsc` shim over a Go + * binary and nothing else, so `typescript` now exports `version` and + * `versionMajorMinor` and no compiler API at all. Every `ts.createSourceFile` + * in this directory started throwing "Cannot read properties of undefined + * (reading 'Latest')" the day the bump landed, and nothing noticed, because no + * workflow runs these. + * + * `typescript-ast` is an npm alias for the last TypeScript that carries the JS + * API (see package.json). It parses; `typescript` still type-checks and builds. + * Two entries, two jobs -- not a version someone forgot to remove. + */ +import ts from "typescript-ast"; import { readFileSync, globSync } from "node:fs"; /** Attributes a person reads. `className` and `key` are not among them. */ diff --git a/scripts/i18n-extract.mjs b/scripts/i18n-extract.mjs index 9960137..acec82b 100644 --- a/scripts/i18n-extract.mjs +++ b/scripts/i18n-extract.mjs @@ -12,7 +12,21 @@ * node scripts/i18n-extract.mjs rewrite in place * node scripts/i18n-extract.mjs --dry */ -import ts from "typescript"; +/* + * The parser, not the compiler. + * + * TypeScript 7 is the native port: its package ships a `tsc` shim over a Go + * binary and nothing else, so `typescript` now exports `version` and + * `versionMajorMinor` and no compiler API at all. Every `ts.createSourceFile` + * in this directory started throwing "Cannot read properties of undefined + * (reading 'Latest')" the day the bump landed, and nothing noticed, because no + * workflow runs these. + * + * `typescript-ast` is an npm alias for the last TypeScript that carries the JS + * API (see package.json). It parses; `typescript` still type-checks and builds. + * Two entries, two jobs -- not a version someone forgot to remove. + */ +import ts from "typescript-ast"; import { readFileSync, writeFileSync } from "node:fs"; const ATTRS = new Set(["title", "aria-label", "placeholder", "alt", "label", "hint", "confirmLabel", "description"]); diff --git a/scripts/i18n-literals.mjs b/scripts/i18n-literals.mjs index d561267..b26e506 100644 --- a/scripts/i18n-literals.mjs +++ b/scripts/i18n-literals.mjs @@ -18,7 +18,21 @@ * string that is neither -- one no catalogue has a key for, which therefore * cannot be translated at all, however many languages ship. */ -import ts from "typescript"; +/* + * The parser, not the compiler. + * + * TypeScript 7 is the native port: its package ships a `tsc` shim over a Go + * binary and nothing else, so `typescript` now exports `version` and + * `versionMajorMinor` and no compiler API at all. Every `ts.createSourceFile` + * in this directory started throwing "Cannot read properties of undefined + * (reading 'Latest')" the day the bump landed, and nothing noticed, because no + * workflow runs these. + * + * `typescript-ast` is an npm alias for the last TypeScript that carries the JS + * API (see package.json). It parses; `typescript` still type-checks and builds. + * Two entries, two jobs -- not a version someone forgot to remove. + */ +import ts from "typescript-ast"; import { readFileSync, globSync } from "node:fs"; /* Where a string literal in this position is shown to somebody. */ diff --git a/scripts/i18n-strings.mjs b/scripts/i18n-strings.mjs index 0089e7a..310a2ad 100644 --- a/scripts/i18n-strings.mjs +++ b/scripts/i18n-strings.mjs @@ -9,7 +9,21 @@ * exists is dead weight, but a call with no key is an untranslated string * nobody noticed. */ -import ts from "typescript"; +/* + * The parser, not the compiler. + * + * TypeScript 7 is the native port: its package ships a `tsc` shim over a Go + * binary and nothing else, so `typescript` now exports `version` and + * `versionMajorMinor` and no compiler API at all. Every `ts.createSourceFile` + * in this directory started throwing "Cannot read properties of undefined + * (reading 'Latest')" the day the bump landed, and nothing noticed, because no + * workflow runs these. + * + * `typescript-ast` is an npm alias for the last TypeScript that carries the JS + * API (see package.json). It parses; `typescript` still type-checks and builds. + * Two entries, two jobs -- not a version someone forgot to remove. + */ +import ts from "typescript-ast"; import { readFileSync, globSync } from "node:fs"; const strings = new Set();