The one where I actually found the badge-translation bug
🏆 Badge titles finally translate — the real root cause
Every non-English user was seeing English badge titles since v1.6.0. I kept adding French/Spanish/German/etc. JSON files. User kept saying "STILL English". I was right that the files were being included, and wrong about everything else.
What actually happened: the Pages/translations/badges.{fr,es,de,it,pt,zh,ja}.json files match MSBuild's *.<culture>.<ext> culture-satellite convention. The build pipeline saw them and moved them OUT of the main DLL and INTO fr/Jellyfin.Plugin.AchievementBadges.resources.dll, de/...resources.dll, etc. — the standard .NET satellite-assembly layout for localized resources.
BadgeLocalizer calls GetManifestResourceStream on the main assembly. Satellites aren't in there. So the lookup returned null, and Localize() silently fell back to English. Forever. For everyone.
Fix: WithCulture="false" + explicit LogicalName on each badge translation file in the .csproj. The main DLL now contains Premier contact, Seigneur du Binge-watching, etc. — verified by searching the DLL bytes directly. No satellite folders in the output.
⚙️ "Loading settings..." finally stops sticking
applyStaticTranslations was calling node.textContent = translation on every [data-i18n] element — which nukes any child elements. The settings container had data-i18n="settings.loading" on its outer div, so every language change silently wiped the rendered settings panel back to a bare "Loading settings..." placeholder.
Fix: applyStaticTranslations now skips nodes that already have child elements. Protects all 11 dynamic-content containers (leaderboard, activity, wrapped, prefs, records, prestige, server stats, bank, daily/weekly quests, settings).
🏅 Equipped-showcase pills forced off for real
v1.7.3's disk-patch fixes handled fresh installs cleanly, but Jellyfin's aggressive index.html caching meant upgraders kept getting served the old bloated inline script that re-creates #ab-sidebar-showcase + #ab-header-badges unconditionally on setInterval.
Fix: sidebar.js now installs a permanent watchdog when the showcase toggle is off — setInterval(250ms) + MutationObserver that removes either element as soon as anything adds it. Idempotent. Cheap. Works even against a stale cached index.html.
👥 Friends button moved to sidebar.js
Visible on every Jellyfin page now, not just the achievements tab. Bottom-left floating button. Standalone.js no longer ships a duplicate.
MD5: 85777C951DE3375FF310502ECBB15A55