From 828323e263dc4f1d59c209cb07a3b83f641ebf49 Mon Sep 17 00:00:00 2001 From: Terry Jia Date: Sat, 7 Feb 2026 21:19:37 -0500 Subject: [PATCH] fix: add post-processing script to fix i18n nodeDefs array corruption (#8718) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary @lobehub/i18n-cli (GPT-4.1) converts numeric-keyed objects like {"0": {...}, "1": {...}} into JSON arrays with null gaps, which crashes vue-i18n path resolution. Add a post-processing step that converts arrays back to objects after translation. ## Screenshots (if applicable) before https://github.com/user-attachments/assets/44e81790-feae-405b-b2c4-098b06a98785 after https://github.com/user-attachments/assets/5d1bd836-c923-437a-aca0-7ebd4d8acb89 image ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8718-fix-add-post-processing-script-to-fix-i18n-nodeDefs-array-corruption-3006d73d365081dab020fea997ec4c0a) by [Unito](https://www.unito.io) --- .github/workflows/i18n-update-core.yaml | 2 +- .../workflows/i18n-update-custom-nodes.yaml | 2 +- .github/workflows/i18n-update-nodes.yaml | 2 +- package.json | 1 + scripts/fix-i18n-node-defs.ts | 66 +++++++++++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 scripts/fix-i18n-node-defs.ts diff --git a/.github/workflows/i18n-update-core.yaml b/.github/workflows/i18n-update-core.yaml index 5f0985b93..38898f014 100644 --- a/.github/workflows/i18n-update-core.yaml +++ b/.github/workflows/i18n-update-core.yaml @@ -43,7 +43,7 @@ jobs: env: PLAYWRIGHT_TEST_URL: http://localhost:5173 - name: Update translations - run: pnpm locale && pnpm format + run: pnpm locale && pnpm fix-i18n-node-defs && pnpm format env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Commit updated locales diff --git a/.github/workflows/i18n-update-custom-nodes.yaml b/.github/workflows/i18n-update-custom-nodes.yaml index 225c1b3e3..4c6788fad 100644 --- a/.github/workflows/i18n-update-custom-nodes.yaml +++ b/.github/workflows/i18n-update-custom-nodes.yaml @@ -67,7 +67,7 @@ jobs: env: PLAYWRIGHT_TEST_URL: http://localhost:5173 - name: Update translations - run: pnpm locale + run: pnpm locale && pnpm fix-i18n-node-defs env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Diff base vs updated i18n diff --git a/.github/workflows/i18n-update-nodes.yaml b/.github/workflows/i18n-update-nodes.yaml index 5a72e5b10..8c974addb 100644 --- a/.github/workflows/i18n-update-nodes.yaml +++ b/.github/workflows/i18n-update-nodes.yaml @@ -36,7 +36,7 @@ jobs: env: PLAYWRIGHT_TEST_URL: http://localhost:5173 - name: Update translations - run: pnpm locale + run: pnpm locale && pnpm fix-i18n-node-defs env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Create Pull Request diff --git a/package.json b/package.json index 643b3c71a..9181a69b9 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dev": "nx serve", "devtools:pycheck": "python3 -m compileall -q tools/devtools", "format:check": "oxfmt --check", + "fix-i18n-node-defs": "tsx scripts/fix-i18n-node-defs.ts", "format": "oxfmt --write", "json-schema": "tsx scripts/generate-json-schema.ts", "knip:no-cache": "knip", diff --git a/scripts/fix-i18n-node-defs.ts b/scripts/fix-i18n-node-defs.ts new file mode 100644 index 000000000..569e79be6 --- /dev/null +++ b/scripts/fix-i18n-node-defs.ts @@ -0,0 +1,66 @@ +import { readFileSync, readdirSync, writeFileSync } from 'fs' +import { join } from 'path' + +const LOCALES_DIR = 'src/locales' + +/** + * Convert arrays with numeric indices back to objects. + * GPT-4.1 (used by @lobehub/i18n-cli) sometimes converts + * {"0": {...}, "1": {...}} objects into JSON arrays with null gaps. + */ +function fixArraysToObjects(value: unknown): Record | unknown { + if (!value || typeof value !== 'object') return value + + if (Array.isArray(value)) { + const obj: Record = {} + for (let i = 0; i < value.length; i++) { + if (value[i] != null) { + obj[String(i)] = fixArraysToObjects(value[i]) + } + } + return obj + } + + const record = value as Record + const result: Record = {} + for (const key of Object.keys(record)) { + result[key] = fixArraysToObjects(record[key]) + } + return result +} + +function run() { + const locales = readdirSync(LOCALES_DIR, { withFileTypes: true }) + .filter((d) => d.isDirectory() && d.name !== 'en') + .map((d) => d.name) + + let totalFixes = 0 + + for (const locale of locales) { + const filePath = join(LOCALES_DIR, locale, 'nodeDefs.json') + let raw: string + try { + raw = readFileSync(filePath, 'utf-8') + } catch { + continue + } + + const data = JSON.parse(raw) + const fixed = fixArraysToObjects(data) as Record + const fixedJson = JSON.stringify(fixed, null, 2) + '\n' + + if (fixedJson !== raw) { + writeFileSync(filePath, fixedJson) + totalFixes++ + console.warn(`Fixed: ${filePath}`) + } + } + + if (totalFixes === 0) { + console.warn('No fixes needed') + } else { + console.warn(`Fixed ${totalFixes} file(s)`) + } +} + +run()