Shipping a second or third language on a web app usually looks straightforward in development: add a [locale] route segment, translate the JSON dictionaries, and deploy.
Then Search Console data starts coming in, and entire language folders sit in "Crawled - currently not indexed" or "Duplicate without user-selected canonical" for weeks.
After debugging several multi-locale setups, here are the five silent failure modes that actually cause non-default locales to stall—and how to catch each one with a single terminal check.
1. Self-Referencing Canonical vs. x-default Mismatches
A common bug in localized layouts is generating the root canonical URL in the shared <head> and forgetting to scope it per route.
If /hu/guide outputs a canonical pointing back to /en/guide, search engines treat the localized page as a duplicate of English and drop it from the index completely. Every localized route must emit a self-referencing canonical, alongside reciprocal hreflang links:
<link rel="canonical" href="https://yoursite.example/hu/guide" /> <link rel="alternate" hreflang="en" href="https://yoursite.example/en/guide" /> <link rel="alternate" hreflang="hu" href="https://yoursite.example/hu/guide" /> <link rel="alternate" hreflang="x-default" href="https://yoursite.example/en/guide" /> Also remember: hreflang must be bidirectional. If /en/guide points to /hu/guide, /hu/guide must point back to /en/guide.
2. Soft 404s From Middleware Locale Fallbacks
A lot of i18n middleware automatically rewrites unknown paths back to /en/... or renders the default locale content while keeping the URL at /hu/old-slug with HTTP 200 OK.
To crawlers, returning English content with HTTP 200 on a localized URL looks like a soft 404 or thin duplicate page.
Rule of thumb:
- If a slug was intentionally translated, never silently serve the English fallback under
/hu/*—redirect (301) or return a genuine404. - Audit your localized sitemap URLs in a script before every deploy and verify every listed URL returns HTTP
200without an unexpected cross-locale redirect.
3. Hardcoded English Metadata (<title>, <meta description>, <html lang>)
Even when the visible React or Vue body renders in the target language, crawlers heavily weight three top-of-document signals:
-
<html lang="hu">(if this stays"en", language classification gets confused) - Localized
<title>and<meta name="description"> - Localized Open Graph tags (
og:title,og:description,og:locale)
If your translation loader runs only on the client inside useEffect, bots inspecting the initial SSR HTML see either blank containers or English fallbacks.
4. Missing Sitemap Cross-Linking or Stale Sub-Sitemaps
Splitting sitemaps per locale (/sitemap-en.xml, /sitemap-hu.xml) is clean—if your root /sitemap.xml actually references them via <sitemapindex>, and every URL inside returns HTTP 200 with matching canonicals.
A surprisingly frequent mistake is adding a localized route, forgetting to include it in the sitemap generator, and leaving zero internal links pointing to it from the default-locale navigation. Orphaned localized pages rarely get crawled beyond initial discovery.
5. Trailing Slashes and Accept-Language Auto-Redirects Blocking Bots
Automatic Accept-Language redirects on the root path (/) can trap search bots whose Accept-Language header is empty or en-US:
- Crawlers from regional instances should be able to reach
/en,/tr, or/hudirectly via stable URLs without being forced into a redirect loop based on cookies or headers. - Pick one trailing-slash convention (
/hu/guidevs/hu/guide/) across routes,<link rel="canonical">,hreflang, andsitemap.xml, and enforce301normalization at the edge.
Quick Terminal Verification Checklist
Before trusting Search Console, run curl against both your localized pages and your sitemap as a stateless client (no cookies, no browser JS):
# 1. Inspect initial HTML lang, canonical, and hreflang tags curl -sL https://yoursite.example/hu/guide | grep -iE "<html|canonical|hreflang|<title" # 2. Verify status codes across all sitemap entries curl -s https://yoursite.example/sitemap.xml | grep -oP '(?<=<loc>)[^<]+' | xargs -I{} curl -o /dev/null -s -w "%{http_code} %{url_effective}\n" {} If initial HTML looks right with JavaScript disabled and every sitemap <loc> returns a clean 200 with self-referencing canonicals, half of multi-locale indexing problems disappear before they ever hit Search Console.
