{"record":{"id":"0a2526b6aa32278d","repo":"cjpais/Handy","slug":"missing-metadata-for-locale-code-in-languages","errorCode":null,"errorMessage":"Missing metadata for locale \"${code}\" in languages.ts","messagePattern":"Missing metadata for locale \"(.+?)\" in languages\\.ts","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/i18n/index.ts","lineNumber":32,"sourceCode":"  \"./locales/*/translation.json\",\n  { eager: true },\n);\n\n// Build resources from discovered locale files\nconst resources: Record<string, { translation: Record<string, unknown> }> = {};\nfor (const [path, module] of Object.entries(localeModules)) {\n  const langCode = path.match(/\\.\\/locales\\/(.+)\\/translation\\.json/)?.[1];\n  if (langCode) {\n    resources[langCode] = { translation: module.default };\n  }\n}\n\n// Build supported languages list from discovered locales + metadata\nexport const SUPPORTED_LANGUAGES = Object.keys(resources)\n  .map((code) => {\n    const meta = LANGUAGE_METADATA[code];\n    if (!meta) {\n      console.warn(`Missing metadata for locale \"${code}\" in languages.ts`);\n      return { code, name: code, nativeName: code, priority: undefined };\n    }\n    return {\n      code,\n      name: meta.name,\n      nativeName: meta.nativeName,\n      priority: meta.priority,\n    };\n  })\n  .sort((a, b) => {\n    // Sort by priority first (lower = higher), then alphabetically\n    if (a.priority !== undefined && b.priority !== undefined) {\n      return a.priority - b.priority;\n    }\n    if (a.priority !== undefined) return -1;\n    if (b.priority !== undefined) return 1;\n    return a.name.localeCompare(b.name);\n  });","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/cjpais/Handy/blob/c89b7bf38974ad317177389f5bfe28236f0d64e3/src/i18n/index.ts#L14-L50","documentation":"At i18n bootstrap, import.meta.glob eagerly loads every src/i18n/locales/<code>/translation.json and turns each directory name into a supported language. This console.warn fires when such a discovered locale code has no matching entry in LANGUAGE_METADATA (src/i18n/languages.ts); the language still works but is listed in the UI with its raw code as both name and nativeName and sorts by that string.","triggerScenarios":"Adding a new locale folder (e.g. src/i18n/locales/pt-BR/translation.json) without adding a pt-BR entry to LANGUAGE_METADATA; a folder whose code differs from the metadata key in case or hyphenation (zh-tw vs zh-TW); leftover experimental locale directories committed by accident.","commonSituations":"Translation contributions (the repo explicitly invites them via CONTRIBUTING_TRANSLATIONS.md) forgetting the metadata step; locale renames; copy-pasting a locale folder as a starting point.","solutions":["Add a metadata entry { name, nativeName, priority? } to LANGUAGE_METADATA in src/i18n/languages.ts keyed by the exact folder code","Use canonical BCP-47 codes consistently between folder name and metadata key (case-sensitive match)","Add a unit test asserting every SUPPORTED_LANGUAGES entry has name !== code, which catches any future occurrence","Remove stray locale folders that are not intended to ship"],"exampleFix":"// before: locales/pt-BR/translation.json exists, languages.ts has no 'pt-BR' key\n//   -> console.warn(`Missing metadata for locale \"pt-BR\" in languages.ts`)\n\n// after: src/i18n/languages.ts\nexport const LANGUAGE_METADATA: Record<string, LanguageMetadata> = {\n  // ...\n  \"pt-BR\": { name: \"Portuguese (Brazil)\", nativeName: \"Português (Brasil)\", priority: 6 },\n};","handlingStrategy":"validation","validationCode":"// Fail the build/test when a locale folder lacks metadata\nimport localeModules from \"virtual:i18n-glob\"; // or replicate the glob in a vitest test\nconst discovered = Object.keys(localeModules).map((p) => p.match(/\\.\\/locales\\/(.+)\\/translation\\.json/)?.[1]);\nconst missing = discovered.filter((c) => c && !(c in LANGUAGE_METADATA));\nif (missing.length) throw new Error(`Missing LANGUAGE_METADATA for: ${missing.join(\", \")}`);","typeGuard":"const isConfiguredLocale = (code: string): code is keyof typeof LANGUAGE_METADATA =>\n  Object.prototype.hasOwnProperty.call(LANGUAGE_METADATA, code);","tryCatchPattern":null,"preventionTips":["Any PR adding src/i18n/locales/<code>/ must also add <code> to LANGUAGE_METADATA in the same PR","Use exact-match BCP-47 codes between folder names and metadata keys (case-sensitive)","Watch the console during first boot of a new locale — this warn is the only signal"],"tags":["i18n","configuration","developer-error","vite"],"backgroundTag":"i18n-locale-metadata-missing","analyzedSha":"c89b7bf38974ad317177389f5bfe28236f0d64e3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}