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
- Ensure i18n-en.ts contains `export const <varName>: Record<string, string> = {` exactly for each varName the script checks
- Update recordKeys' regex (or the script's varName list) to match the new declaration style or file
- If the type changed (e.g. satisfies/as const), relax the regex to accept it
- 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
- Keep the exported `: Record<string, string> = {` annotation style when editing i18n-en.ts
- Update i18n-verify.mjs whenever dictionary names, files, or type annotations change
- Run the i18n verify script in CI to catch renames early
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)