BigPizzaV3/CodexPlusPlus · error · Error

Could not find in i18n-en.ts

Error message

Could not find ${varName} in i18n-en.ts

What it means

tools/i18n-verify.mjs reads src/i18n-en.ts and locates each exported dictionary via a regex `export const ${varName}: Record<string, string> = {`. If the regex doesn't match, it throws `Could not find ${varName} in i18n-en.ts`, meaning the expected exported Record declaration is absent or formatted differently.

Solutions

  1. Ensure i18n-en.ts contains `export const <varName>: Record<string, string> = {` exactly for each varName the script checks
  2. Update recordKeys' regex (or the script's varName list) to match the new declaration style or file
  3. If the type changed (e.g. satisfies/as const), relax the regex to accept it
  4. Verify the script's appRoot points at the app whose src/i18n-en.ts you edited

Example fix

// before
export const MESSAGES = { ... } satisfies Record<string, string>;
// after
export const MESSAGES: Record<string, string> = { ... };
Defensive patterns

Strategy: try-catch

Validate before calling

if (!/export const MESSAGES\s*:\s*Record<string,\s*string>\s*=\s*\{/.test(dictSource)) throw new Error('MESSAGES declaration not found in i18n-en.ts');

Try / catch

try { const keys = recordKeys('MESSAGES'); } catch (e) { if (String(e.message).startsWith('Could not find')) { console.error('i18n dict missing/renamed:', e.message); process.exit(1); } throw e; }

Prevention

When it happens

Trigger: recordKeys('MESSAGES') (or another varName) run against an i18n-en.ts that lacks `export const MESSAGES: Record<string, string> = {` — the dict was renamed, moved to another file, typed differently (e.g. `satisfies Record<...>`), or formatted with different spacing/line breaks the regex can't span.

Common situations: Refactoring i18n-en.ts to use a different type annotation or `as const`; renaming the export; splitting dictionaries into multiple files while the verify script still expects them in i18n-en.ts; prettier reformatting that breaks the single-line pattern.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/810c553611994ec4. Report an issue: GitHub.

Appendix: source

Thrown at tools/i18n-verify.mjs:62

        // tr 是 vlm-test-translation.ts 注入的翻译回调:1 参->plain,2 参->template。
        if (fn === "t" || (fn === "tr" && node.arguments.length === 1)) usedPlain.add(literal);
        else if (fn === "tf" || (fn === "tr" && node.arguments.length >= 2)) usedTemplate.add(literal);
      }
    }
    ts.forEachChild(node, visit);
  };
  visit(sf);
}

for (const f of SRC_FILES) scanFile(f);

// ── Read the dictionary keys out of i18n-en.ts. ─────────────────────────────
const dictSource = readFileSync(path.join(appRoot, "src", "i18n-en.ts"), "utf8");

function recordKeys(varName) {
  const re = new RegExp(`export const ${varName}\\s*:\\s*Record<string,\\s*string>\\s*=\\s*\\{`);
  const match = re.exec(dictSource);
  if (!match) throw new Error(`Could not find ${varName} in i18n-en.ts`);
  const start = match.index + match[0].length - 1; // position of "{"
  let depth = 0;
  let i = start;
  let inStr = null;
  let escaped = false;
  for (; i < dictSource.length; i++) {
    const ch = dictSource[i];
    if (inStr) {
      if (escaped) escaped = false;
      else if (ch === "\\") escaped = true;
      else if (ch === inStr) inStr = null;
      continue;
    }
    if (ch === '"' || ch === "'" || ch === "`") inStr = ch;
    else if (ch === "{") depth++;
    else if (ch === "}") {
      depth--;
      if (depth === 0) { i++; break; }

View on GitHub (pinned to b1ed92e5e4)