What's fixed
⏳ Hero subtitle stuck on "Loading..."
loadAll's Promise.all had six unguarded fetches. Any one of them hitting a 429 (rate-limit) or 5xx rejected the whole Promise.all, so the .then that populates the subtitle, the stats boxes, and a dozen other panels never ran. Now every fetch has its own .catch with a safe default — the UI always finishes rendering.
🌍 Admin badge titles finally translate too
/admin/badge-catalog now accepts ?lang= and runs every definition through BadgeLocalizer. The admin page passes the user's saved language (from localStorage.achievementBadgesLang) automatically. French admin now sees "Premier contact", "Seigneur du Binge-watching", etc. in the Enable/disable grid.
📊 Rarity % chip on every badge card (new)
You asked for a percentage instead of a heatmap. Done. Each badge card shows a coloured chip with a groups icon + the % of users on your server who've unlocked that badge:
- Green ≥ 50%
- Amber 10–50%
- Red < 10%
Fed by a new /badges/rarity-stats endpoint with a 5-minute in-memory cache, so it doesn't re-scan every profile on every page load. Fetched in parallel with the rest of loadAll — if the stats fetch fails, the chip just doesn't render, nothing else breaks.
MD5: FEA99E314FF86A053D939ABD36F26537