Adds quick language filters (English, Japanese, Chinese) to nhentai pages — works with SvelteKit SPA navigation
Adds one-click language filter buttons to every nhentai.net listing page.
| Script file | nhentai Language Filter.txt |
| Author | Snow2122 |
| Version | 1.2.0 |
| License | MIT |
| Updated | 2026-04-01 |
| Applies to | nhentai.net |
A userscript that injects English Only, Japanese Only, Chinese Only, and All filter buttons directly onto nhentai.net listing pages. Clicking a filter navigates to the matching search query using nhentai's own SPA router — no forced page reloads. Filters reappear automatically after every client-side navigation, and persist through SvelteKit's hydration re-renders.
| Feature | Description |
|---|---|
| Namespace page filters | Inline filter buttons added to the sort bar on tag, artist, character, parody, group, and category pages |
| Search page filters | Same filter buttons on search result pages — the active language is highlighted in red |
| Favorites page filters | Compact flag buttons (🇬🇧 EN / 🇯🇵 JP / 🇨🇳 CN / 🌍 ALL) next to the random button |
| Homepage dropdown | A 🌐 Language ▾ hover dropdown in the navigation bar for instant language-filtered browsing from the home page |
| SPA navigation support | Filters are re-injected automatically after every SvelteKit client-side navigation |
| Hydration resilience | A permanent MutationObserver watches the DOM and re-injects filters if SvelteKit's hydration pass wipes them |
| Clean navigation | Filter links use nhentai's SPA router — browsing stays smooth with no full reloads |
| State tracking | Injected elements carry a data-nhi-lang marker for reliable detection and clean removal on navigation |
| Page | URL Pattern | Filter Style |
|---|---|---|
| Home | nhentai.net/ |
🌐 Dropdown in nav bar |
| Search results | nhentai.net/search?q=… |
Buttons in sort bar |
| Tag pages | nhentai.net/tag/… |
Buttons in sort bar |
| Artist pages | nhentai.net/artist/… |
Buttons in sort bar |
| Character pages | nhentai.net/character/… |
Buttons in sort bar |
| Parody pages | nhentai.net/parody/… |
Buttons in sort bar |
| Group pages | nhentai.net/group/… |
Buttons in sort bar |
| Favorites | nhentai.net/user/favorites/ |
🚩 Flag buttons next to random |
| Manager | Supported browsers |
|---|---|
| Tampermonkey | Chrome, Firefox, Edge, Opera |
| Violentmonkey | Chrome, Firefox, Edge |
| Greasemonkey | Firefox |
nhentai Language Filter.txt and paste it inCtrl + S or click the Save buttonLanguage filter buttons appear automatically inline with the sort bar:
[ Recent ] Popular: today week all time | English Only Japanese Only Chinese Only All
Clicking English Only on /tag/cheating/ navigates to:
/search?q=tag%3Acheating+language:english
The same filter buttons appear on that search results page, with English Only highlighted in red to show the active filter. Clicking All removes the language restriction and returns to the unfiltered tag results.
Filter buttons appear in the sort bar. The currently active language filter (if any) is highlighted in red.
[ Recent ] Popular: today week all time | English Only* Japanese Only Chinese Only All
* = highlighted in red
A 🌐 Language ▾ dropdown appears in the right side of the navigation bar. Hover over it to open:
🌐 Language ▾
┌─────────────┐
│ 🇬🇧 English │
│ 🇯🇵 Japanese │
│ 🇨🇳 Chinese │
│ 🌍 All │
└─────────────┘
Clicking a language navigates to the corresponding search page (e.g. /search?q=language:english).
Flag buttons appear next to the random button inside your favorites:
🎲 Random | 🇬🇧 EN 🇯🇵 JP 🇨🇳 CN 🌍 ALL
These filter your saved favorites by language and persist through paginated browsing.
Navigation detection — The script patches history.pushState, history.replaceState, and popstate so it is notified of every SvelteKit client-side navigation.
Staggered injection passes — On each navigation (and on initial load), checkAndInject() is called at six independent delays: 0 ms, 150 ms, 400 ms, 800 ms, 1500 ms, 2500 ms. These use direct setTimeout calls, not a shared debounce timer, so the MutationObserver can never cancel them.
Hydration recovery — A permanent MutationObserver watches document.body for any DOM changes (80 ms debounce, independent timer). If SvelteKit's hydration wipes injected elements, the observer detects the change and immediately re-injects.
Page type detection — checkAndInject() reads window.location.pathname and calls the appropriate injector:
| Pathname pattern | Injector | Target element |
|---|---|---|
| /tag/, /artist/, /character/, etc. | injectNamespace() | .sort div |
| /search | injectSearch() | .sort div |
| /user/favorites/ | injectFavorites() | Next to #favorites-random-button |
| / | injectHomepage() | .menu.right nav |
data-nhi-lang="<code>" set on it. Before injecting for a new page, all elements with this attribute from the previous page are removed. If elements for the current page are already present, the injection is skipped.The filter buttons generate URLs in this format:
| Context | Generated URL |
|---|---|
| Tag page → English | /search?q=tag%3A{slug}+language:english |
| Tag page → All | /tag/{slug}/ (original URL, no language filter) |
| Search page → Japanese | /search?q={existing query} language:japanese |
| Search page → All | /search?q={query without language term} |
| Home page → Chinese | /search?q=language:chinese |
| Favorites → English | /user/favorites/?q=language:english |
The stripLanguage() helper removes any existing language:xxx term from the current query before adding the new one, so switching between languages never stacks multiple language filters.
Full SPA compatibility rewrite.
history.pushState / replaceState and popstateMutationObserver for hydration resilience (80 ms debounce, independent timer)onNavigate() fires injection at six independent staggered delays — the MutationObserver debounce cannot cancel them/search?q=…) — active language highlighted in reddata-nhi-lang marker attribute on every injected element for reliable clean-up on navigationpathname.startsWith("/search") replaces the old regex that required a trailing slash — correctly matches /search?q=… without trailing slash/search?q=… (no trailing slash before ?) to match actual SvelteKit URL formatlastKey updated before the injection attempt (not only on success) — retry passes skip cleanup and go straight to injectionmuteTimer (its own independent timer) separate from navigation schedules@match https://nhentai.net/search* replaces search/* to cover URLs without trailing slashinjectNamespace)injectHomepage)stripLanguage() helper removes existing language terms before applying a new filterbuildSortItem() and buildSortAll() element builders for reusable sort-type divsLicensed under the MIT License. You are free to use, modify, and distribute this script for any purpose provided the original copyright notice is retained.
Snow2122