--- name: /api/rules localization description: The static rule catalog endpoint must localize text by lang query param, not just scan findings. --- The DB rule catalog is seeded in German; runtime localization lives in `localizeRule(ruleId, lang)` (ruleCatalogI18n.ts). Two separate surfaces consume rules and BOTH must localize: 1. Scan findings — localized inside the scan engine by the scan's stored language. 2. `GET /api/rules` — the public education/catalog section and the admin rules tab render the raw catalog. This endpoint must accept a `lang` query param and run each row through `localizeRule`, else it leaks German into EN/ES UIs even when everything else is translated. **Why:** UI string externalization alone is not enough — any API that returns catalog/domain text needs its own language plumbing. The "rules come from the API, already localized" assumption was false for the list endpoint (only findings were wired). **How to apply:** Frontend passes `{ lang: currentLanguage() }` to `useListRules`; because the calling components use `useTranslation`, a language switch re-renders, changes the query param, and refetches. When adding any new endpoint that returns rule/category/domain text, localize by an explicit `lang` param.