2023 में मैंने बर्लिन स्थित एक क्लाइंट के लिए एक बहुभाषी ई-कॉमर्स साइट लॉन्च की थी। बारह भाषाएं, App Router, सब कुछ साफ-सुथरा लग रहा था। तीन महीने बाद उनके जर्मन प्रोडक्ट पेज यूके के SERPs में रैंक कर रहे थे और उनके अंग्रेजी पेज मुंबई के उपयोगकर्ताओं को serve हो रहे थे। hreflang tags तकनीकी रूप से मौजूद थे। वे सिर्फ इस तरह गलत थे कि मुझे एक शर्मनाक दोपहर इसे सुलझाने में लगी। उस अनुभव ने मुझे किसी भी documentation page से कहीं ज़्यादा Next.js i18n के बारे में सिखाया।
यह "यहाँ official docs को सारांशित किया गया है" वाली post नहीं है। यह वह है जो मैंने Seahawk Media में बहुभाषी साइटें बनाते हुए सीखा है, जो चीजें लोगों को बार-बार काटती हैं, और वह विशिष्ट निर्णय जो 2026 में वाकई rankings को प्रभावित करते हैं।
---
App Router ने सब कुछ बदल दिया (और सब कुछ अच्छे के लिए नहीं)
Pages Router के पास built-in i18n support था। आप next.config.js में एक block डालते थे और Next.js लगभग स्वचालित रूप से locale detection, sub-path routing, और Link component locale switching को संभालता था। यह परिपूर्ण नहीं था, लेकिन यह opinionated था, जिसका मतलब था कम footguns।next.config.js and Next.js handled locale detection, sub-path routing, and Link component locale switching almost automatically. It wasn't perfect, but it was opinionated, which meant fewer footguns.
App Router ने native i18n routing को पूरी तरह हटा दिया है। next.config.js में कोई i18n key नहीं। कोई automatic locale detection नहीं। अब आप पूरे routing logic के लिए जिम्मेदार हैं, और यही वह जगह है जहाँ ज्यादातर teams चुपचाप गड़बड़ कर देती हैं।i18n key in next.config.js. No automatic locale detection. You are now responsible for the full routing logic, and that responsibility is where most teams quietly make a mess.
2026 में सबसे मान्य तरीका आपकी app/ directory के root में [locale] dynamic segment का उपयोग करना है। कुछ इस तरह: app/[locale]/page.tsx। इसे next-intl या i18next के साथ react-i18next के माध्यम से जोड़ दें, एक middleware file जो Accept-Language headers को पढ़े और accordingly redirect करे, और आपके पास एक काम करने वाली foundation है।[locale] dynamic segment at the root of your app/ directory. Something like app/[locale]/page.tsx . Pair that with next-intl or i18next via react-i18next, a middleware file that reads Accept-Language headers and redirects accordingly, and you have a working foundation.
Middleware को गलतफहमी क्यों होती है
Middleware file दो अलग-अलग काम कर रही है जिन्हें लोग एक मानते हैं। पहला, locale detection: Accept-Language header (या एक cookie, या एक URL prefix) को पढ़ना और यह तय करना कि कौन सा locale serve करना है। दूसरा, URL को redirect या rewrite करना ताकि user /produkte के बजाय /de/produkte पर पहुँचे, कुछ hidden locale state के साथ नहीं।Accept-Language header (or a cookie, or a URL prefix) and deciding which locale to serve. Second, redirecting or rewriting the URL so the user ends up at /de/produkte rather than /produkte with some hidden locale state.
दोनों को page render होने से पहले होना चाहिए। यह obvious लगता है। लेकिन मैंने teams को locale detection को React context provider के अंदर चलाते हुए देखा है, जिसका मतलब है कि Googlebot को serve किया गया initial HTML के पास कोई locale signal ही नहीं है। Bot को एक page दिखता है, वह इसे root URL के तहत index करता है, और अचानक आपके पास एक canonical mess हो जाता है।before the page renders. That sounds obvious. But I've seen teams run locale detection inside a React context provider, which means the initial HTML served to Googlebot has no locale signal at all. The bot sees a page, it indexes it under the root URL, and suddenly you have a canonical mess.
Locale resolution को middleware में रखें। हमेशा।
---
Sub-path vs Sub-domain: एक चुनें और प्रतिबद्ध रहें
यह अनंत बहस है। /en/about बनाम en.yoursite.com/about। अधिकांश projects के लिए मैं sub-path routing की सलाह देता हूँ, और यह कारण है: यह आपके domain authority को केंद्रित करता है। आपके .com की ओर pointing करने वाली हर link सभी locales को फायदा पहुँचाती है। Sub-domains के साथ आप Google की नजर में effectively अलग-अलग sites चला रहे हैं, जिसका मतलब है कि आपको प्रत्येक के लिए independently authority build करनी पड़ती है।/en/about vs en.yoursite.com/about . For most projects I recommend sub-path routing, and here's why: it concentrates your domain authority. Every link pointing at your .com benefits all locales. With sub-domains you're effectively running separate sites in Google's eyes, which means you need to build authority for each one independently.
एक exception है। अगर आप एक ऐसे market में हैं जहाँ local TLD trust के लिए भारी मायने रखता है (.de Germany में, .fr France में), तो country-code TLD sub-paths और sub-domains दोनों को perceived local credibility के लिए मात देता है। यह एक SEO claim नहीं है, यह एक conversion claim है। मैंने A/B tests देखे हैं जहाँ .de बनाम yourbrand.com/de ने trust metrics को meaningfully आगे बढ़ाया, भले ही rankings identical थे।.de in Germany, .fr in France), a country-code TLD beats both sub-paths and sub-domains for perceived local credibility. That's not an SEO claim, it's a conversion claim. I've seen A/B tests where .de vs yourbrand.com/de moved trust metrics meaningfully even when rankings were identical.
लेकिन आप एक ccTLD सेटअप को एक single Next.js app के अंदर आसानी से run नहीं कर सकते। तो 99% projects के लिए: sub-paths, एक app, एक domain।
---
hreflang: वह Tag जो आपसे झूठ बोलता है
यह वह जगह है जहाँ मुझे सबसे ज्यादा नुकसान दिखता है। hreflang conceptually मुश्किल नहीं है। यह search engines को बताता है: "इस page के अन्य भाषाओं में समतुल्य हैं, ये रहे।" व्यवहार में, implementation के तीन specific failure modes हैं जो मुझे बार-बार मिलते हैं।
Failure Mode 1: Tags एक-दूसरे को Reference नहीं करते
आपके hreflang set के हर page को दूसरे सभी pages को reference करना चाहिए, अपने आप को भी। अगर /en/about के पास /de/about की ओर pointing करने वाला hreflang है लेकिन /de/about के पास /en/about की ओर pointing करने वाला hreflang नहीं है, तो Google पूरे set को ignore कर देता है। Penalise नहीं करता। Ignore करता है। जैसे कि tags exist ही नहीं करते।/en/about has an hreflang pointing to /de/about but /de/about does not have an hreflang pointing back to /en/about, Google ignores the whole set. Not penalises. Ignores. As if the tags don't exist.
Seahawk के पास पिछले साल एक fintech project था जहाँ 40% hreflang tags non-reciprocal थे क्योंकि दो developers ने independently उन्हें different components में implement किया था बिना coordinate किए। Fix को एक घंटा लगा। Rankings recovery को दो महीने लगे।
Failure Mode 2: x-default Tag गायब या गलत जगह पर है
x-default उन pages के लिए है जो किसी specific language या region को target नहीं करते। आमतौर पर आपका root / या एक language-selector page। कुछ teams अपने English page पर x-default रखते हैं, जो ठीक है अगर English genuinely आपका fallback है सभी unmatched locales के लिए। लेकिन अगर आप ऐसे users को एक different page serve करते हैं जिनकी language आप support नहीं करते, तो x-default को वहाँ point करना चाहिए। is for pages that don't target a specific language or region. Typically your root / or a language-selector page. Some teams put x-default on their English page, which is fine if English is genuinely your fallback for all unmatched locales. But if you serve a different page to users whose language you don't support, x-default should point there.
मैंने x-default को completely omit होते हुए देखा है। Google कोई error throw नहीं करता। यह सिर्फ अपना निर्णय लेता है कि unmatched queries के लिए कौन सा version दिखाना है, और वह निर्णय अक्सर गलत होता है।x-default omitted entirely. Google doesn't throw an error. It just makes its own decision about which version to show for unmatched queries, and that decision is often wrong.
विफलता मोड 3: ट्रेलिंग स्लैश और कैनोनिकल कॉन्फ्लिक्ट
आपका hreflang टैग कहता है https://yoursite.com/de/ueber-uns। उसी पेज पर आपका canonical टैग कहता है https://yoursite.com/de/ueber-uns/ (ध्यान दें ट्रेलिंग स्लैश)। Google उन्हें अलग-अलग URLs मानता है। अब आपका canonical और hreflang अलग-अलग चीजों की ओर इशारा कर रहे हैं, और आपने एक सिग्नल कॉन्फ्लिक्ट बना दिया है जो रैंकिंग को चुपचाप दबाता है बिना Search Console में कोई दिखने वाली त्रुटि दिए।https://yoursite.com/de/ueber-uns . Your canonical tag on the same page says https://yoursite.com/de/ueber-uns/ (note the trailing slash). Google treats those as different URLs. Your canonical and hreflang are now pointing at different things, and you've created a signal conflict that quietly suppresses rankings without any visible error in Search Console.
next.config.js में trailingSlash सेट करें और हर जगह consistent रहें। जांचें। वाकई अपने URLs को curl करके और आउटपुट पढ़कर जांचें।trailingSlash in next.config.js and be consistent everywhere. Check it. Actually check it by curling your own URLs and reading the output.
Google Search Central का hreflang पर documentation सच में पूरा पढ़ने लायक है। यह उन दुर्लभ official docs में से एक है जो काफी specific है कि उपयोगी हो सके।Google Search Central documentation on hreflang is genuinely worth reading in full. It's one of those rare official docs that's specific enough to be useful.
---
Next.js में बड़े पैमाने पर hreflang जेनरेट करना
5-भाषा की साइट के लिए आप hreflang टैग हाथ से लिख सकते हैं। 12 locales में 3,000 product pages के लिए, आपको एक systematic approach चाहिए।
यहाँ मैं जो use करता हूँ:
- अपनी locale लिस्ट एक बार, एक single config file में define करें। कुछ इस तरह locales.config.ts export करते हुए एक array: ['en', 'de', 'fr', 'es', 'nl'...]।
locales.config.tsexporting an array:['en', 'de', 'fr', 'es', 'nl'...]. - एक utility function getHreflangAlternates(pathname: string) build करें जो एक locale-agnostic path (/about) लेता है और हर locale के लिए { hreflang, href } objects का एक array return करता है।
getHreflangAlternates(pathname: string)that takes a locale-agnostic path (/about) and returns an array of{ hreflang, href }objects for every locale. - इस फंक्शन को अपने root layout.tsx में कॉल करें और Next.js के metadata API का उपयोग करके alternates.languages फील्ड के जरिए परिणामों को इंजेक्ट करें। यह Next.js 13.3 में जोड़ा गया था और यह <head> में स्वचालित रूप से सही <link rel="alternate" hreflang="..."> टैग जेनरेट करता है।
layout.tsxand inject the results via Next.js'smetadataAPI using thealternates.languagesfield. This was added in Next.js 13.3 and it generates the correct<link rel="alternate" hreflang="...">tags in<head>automatically. - डायनामिक कंटेंट वाले पेजों के लिए (ब्लॉग पोस्ट, प्रोडक्ट पेज) जहाँ हर लोकेल का ट्रांसलेशन नहीं है, अपनी यूटिलिटी को supportedLocales एरे पास करें और केवल उन लोकेल्स के लिए टैग जेनरेट करें जहाँ कंटेंट वास्तव में मौजूद है। एक hreflang टैग जो 404 रिटर्न करने वाले पेज की ओर इशारा करता है, कोई hreflang टैग न होने से बदतर है।
supportedLocalesarray to your utility and only generate tags for locales where the content actually exists. A hreflang tag pointing to a page that returns 404 is worse than no hreflang tag.
metadata API में alternates.languages अप्रोच इसे हैंडल करने का सबसे क्लीन तरीका है जो मुझे मिला। कोई कस्टम <Head> जुगाड़ नहीं, टैग्स के लिए कोई थर्ड-पार्टी पैकेज नहीं।alternates.languages approach in the metadata API is the cleanest way I've found to handle this. No custom <Head> juggling, no third-party packages for the tags themselves.
---
लोकेल डिटेक्शन बिना परेशान किए
यहाँ एक UX ट्रैप है जिसके SEO प्रभाव भी हैं। ब्राउजर लोकेल के आधार पर आक्रामक ऑटोमेटिक रीडायरेक्शन दोनों के लिए ही खराब है।
अगर जर्मनी में कोई यूजर yoursite.com/en/article विज़िट करता है और आपका मिडलवेयर उन्हें बिना पूछे /de/artikel पर हार्ड-रीडायरेक्ट कर देता है, तो आपने उनके इरादे को तोड़ दिया है। आपने लिंक शेयरिंग को भी संभावित रूप से तोड़ दिया है: कोई अंग्रेजी URL शेयर करता है, फ्रांस में प्राप्तकर्ता को फ्रेंच पर भेज दिया जाता है, और जो कंटेंट उन्हें दिखाया जाना था वह फ्रेंच में अभी मौजूद नहीं हो सकता।yoursite.com/en/article and your middleware hard-redirects them to /de/artikel without asking, you've just broken their intended navigation. You've also potentially broken link sharing: someone shares the English URL, the recipient in France gets bounced to French, and the content they were meant to see might not exist in French yet.
मेरा नियम: डिटेक्ट करें, सुझाव दें, जबरदस्ती न करें। पहली विज़िट पर Accept-Language हेडर का उपयोग करके एक समझदारी भरा डिफ़ॉल्ट सेट करें (कुकी में स्टोर किया गया), लेकिन यूजर्स को मैन्युअली ओवरराइड करने दें और हर बाद की विज़िट पर उस ओवरराइड को सम्मान दें। कुकी हेडर पर प्राथमिकता लेती है।detect, suggest, don't force. Use the Accept-Language header to set a sensible default on first visit (stored in a cookie), but let users override it manually and honour that override on every subsequent visit. The cookie takes priority over the header.
SEO के लिए विशेष रूप से: Googlebot साथ में सार्थक Accept-Language हेडर नहीं भेजता। यह आपके URLs को जैसे हैं वैसे ही क्रॉल करेगा। तो सुनिश्चित करें कि हर लोकेल URL सीधे एक्सेसिबल है बिना रीडायरेक्शन के, और आपका sitemap सभी लोकेल वेरिएंट को स्पष्ट रूप से शामिल करता है।Accept-Language headers. It will crawl your URLs as-is. So make sure every locale URL is directly accessible without redirection, and that your sitemap includes all locale variants explicitly.
next-intl मिडलवेयर डॉक्यूमेंटेशन इस डिटेक्शन स्ट्रैटेजी को अच्छी तरह कवर करता है, और यह वह जगह है जहाँ मैं किसी को नई प्रोजेक्ट शुरू करते समय भेजता।next-intl middleware documentation covers this detection strategy well, and it's where I'd send anyone starting a new project.
---
बहुभाषी साइटों के लिए साइटमैप
एक साथ हर लोकेल वेरिएंट को शामिल करने वाला sitemap.xml छोटी साइटों के लिए ठीक है। बड़ी साइटों के लिए (कई लोकेल्स में हजारों URL) मैं इसे विभाजित करता हूँ: /sitemap.xml पर एक sitemap इंडेक्स, फिर /sitemaps/en.xml, /sitemaps/de.xml आदि में प्रति लोकेल अलग sitemap फ़ाइलें।sitemap.xml that includes every locale variant is fine for smaller sites. For large sites (tens of thousands of URLs across multiple locales) I split it: one sitemap index at /sitemap.xml , then separate sitemap files per locale at /sitemaps/en.xml , /sitemaps/de.xml, and so on.
हर URL एंट्री में <xhtml:link rel="alternate"> टैग होने चाहिए जो आपकी hreflang सेटअप को दर्शाते हों। यह पेज के अंदर के टैग के साथ अनावश्यक है लेकिन यह Googlebot को ऐसे पेजों को जोड़ने में मदद करता है जिन्हें इसने अभी क्रॉल नहीं किया है।<xhtml:link rel="alternate"> tags mirroring your hreflang setup. This is redundant with the in-page tags but it helps Googlebot connect the dots on pages it hasn't crawled yet.
Next.js 14+ में आप app/sitemap.ts के माध्यम से sitemap को डायनामिकली जेनरेट कर सकते हैं। रिटर्न टाइप metadata API के समान शेप में alternates.languages को सपोर्ट करता है। इसे उसी getHreflangAlternates यूटिलिटी से कनेक्ट करें जो आपने पहले बनाई थी और आपको मुफ्त में कंसिस्टेंसी मिल जाती है।app/sitemap.ts . The return type supports alternates.languages in the same shape as the metadata API. Wire it up to the same getHreflangAlternates utility you built earlier and you get consistency for free.
एक ठोस संख्या: 8 लोकेल्स और 4,500 प्रोडक्ट्स वाली एक प्रोजेक्ट पर, sitemap को विभाजित करने से GSC क्रॉल स्टैट्स के आधार पर प्रति लोकेल औसत क्रॉल समय में लगभग 30% की कमी आई। बहुत बड़ी बात नहीं है, लेकिन मायने रखती है।
---
ट्रांसलेशन लाइब्रेरीज: मैं वास्तव में क्या यूज करता हूँ
तीन लाइब्रेरीज लायक हैं जानने के लिए। next-intl मेरा App Router प्रोजेक्ट्स के लिए डिफ़ॉल्ट है। इसमें server components के लिए फर्स्ट-क्लास सपोर्ट है, प्लूरलाइजेशन को सही तरीके से हैंडल करता है, और API क्लीन है। मैंने इसे मध्य-2023 के बाद से लगभग 40 प्रोजेक्ट्स पर यूज किया है।next-intl is my default for App Router projects. It has first-class support for server components, handles pluralisation properly, and the API is clean. I've used it on about 40 projects since mid-2023.
react-i18next युद्ध-परीक्षित है और इसका एक बहुत बड़ा इकोसिस्टम है, लेकिन इसका मानसिक मॉडल क्लाइंट components के लिए बनाया गया था और i18next कोर के माध्यम से server component सपोर्ट जोड़ना next-intl के नेटिव अप्रोच की तुलना में bolted-on लगता है।i18next core feels bolted-on compared to next-intl's native approach.
Lingui को देखना लायक है अगर आपके अनुवाद workflow में पेशेवर अनुवादक शामिल हैं, CMS नहीं। इसका extraction tooling बेहतर है। लेकिन ज्यादातर agency projects के लिए जहाँ content Contentful या Sanity से आता है, next-intl ज्यादा सरल है।
जिससे मैं बचता हूँ: अपना खुद का बनाना। मैंने 2020 में एक बार ऐसा किया था जहाँ client ने जोर दिया कि उनकी मौजूदा PHP translation files सीधे दुबारा इस्तेमाल की जाएँ। यह काम किया, मुश्किल से, और मैंने दो साल कुछ maintain करते हुए गँवा दिए जिसे next-intl अब एक single useTranslations() call में handle करता है।useTranslations() call.
---
FAQ
क्या Next.js App Router पुरानी `next.config.js` i18n block को support करता है?
नहीं। i18n configuration key Pages Router के लिए विशেष था। अगर आप App Router में migrate कर रहे हैं, तो आपको एक [locale] dynamic segment और middleware file के जरिए routing implement करनी होगी। पुरानी config block को App Router projects में चुपचाप ignore किया जाता है।i18n configuration key was specific to the Pages Router. If you're migrating to App Router, you need to implement routing via a [locale] dynamic segment and a middleware file. The old config block is silently ignored in App Router projects.
क्या मुझे URL path में `lang` इस्तेमाल करना चाहिए या subdomains पर निर्भर रहना चाहिए?
ज्यादातर projects के लिए, URL path में lang (sub-path routing जैसे /de/) सही call है। Subdomains आपके domain authority को तोड़ते हैं और अलग DNS configuration की ज़रूरत होती है। ccTLDs सिर्फ इस complexity के लायक हैं अगर local trust signals genuinely आपके specific markets में conversion rates को बढ़ा रहे हों।lang in the URL path (sub-path routing like /de/) is the right call. Subdomains fragment your domain authority and require separate DNS configuration. ccTLDs are only worth the complexity if local trust signals are genuinely moving conversion rates in your specific markets.
Googlebot JavaScript-rendered locale content को कैसे handle करता है?
ख़राब, कभी-कभी। अगर आपका locale detection पूरी तरह client-side एक React context में चलता है और initial HTML में कोई locale marker नहीं है, तो Googlebot pre-hydration state को index कर सकता है। हमेशा locale को middleware में resolve करें और सुनिश्चित करें कि सही lang attribute server-rendered HTML में <html> element पर है। इसे browser devtools का इस्तेमाल करके नहीं, source को देखकर check करें (जो post-hydration state दिखाते हैं)।lang attribute is on the <html> element in the server-rendered HTML. Check this by viewing source, not by using browser devtools (which show post-hydration state).
किसी साइट के लिए सही `x-default` hreflang वैल्यू क्या है जिसके पास कोई लैंग्वेज सिलेक्टर पेज नहीं है?
इसे आपने प्राइमरी लोकेल के होमपेज की ओर इंगित करें, आमतौर पर /en/। यह Google को सिग्नल देता है कि अंग्रेजी उन यूजर्स के लिए आपका फॉलबैक है जिनकी लैंग्वेज आप सपोर्ट नहीं करते। ऐसा करना कोई पेनल्टी नहीं है, यह सिर्फ एक सॉफ्ट प्रेफरेंस सिग्नल है जिसे Google मान भी सकता है और नहीं भी।/en/. It signals to Google that English is your fallback for users whose language you don't support. It's not a penalty to do this, it's just a soft preference signal Google may or may not honour.
क्या मैं बिना किसी पेड SEO टूल के अपने hreflang इंप्लीमेंटेशन को वेरिफाई कर सकता हूँ?
हाँ। Google Search Console का URL Inspection टूल किसी भी इंडेक्स किए गए URL के लिए पहचाने गए hreflang टैग दिखाएगा। यह रिसिप्रोसिटी को ऑटोमैटिक रूप से वेलिडेट नहीं करेगा, लेकिन आप कुछ रेप्रेजेंटेटिव पेज को मैन्युअली चेक कर सकते हैं। बल्क वेलिडेशन के लिए, Screaming Frog (500 URLs तक फ्री) अपने hreflang टैब में रिसिप्रोसिटी चेक को हैंडल करता है।Google Search Console's URL Inspection tool will show you detected hreflang tags for any indexed URL. It won't validate reciprocity automatically, but you can manually check a few representative pages. For bulk validation, Screaming Frog (free up to 500 URLs) handles reciprocity checks in its hreflang tab.
---
मल्टीलिंग्वुअल Next.js को सही तरीके से सेटअप करना वास्तव में उबाऊ काम है। यह कॉन्फ़िग फाइलें, URL कंसिस्टेंसी, और यह सुनिश्चित करना है कि दो डेवलपर्स ने एक ही चीज को दो अलग-अलग कॉम्पोनेंट में इंप्लीमेंट नहीं किया है। लेकिन जिन साइट्स पर मैंने इसे सही तरीके से करने में समय लगाया है, उनकी रैंकिंग पूरे रीजन में स्थिर रहती है, और जिन पर मैंने कोनों में कटौती की है, उन्होंने मुझे वे सीख सिखाई है जो मैंने यहाँ लिखी है।
बर्लिन क्लायंट, वैसे, आखिरकार अपने जर्मन पेज को जर्मनी में रैंक करवाने में कामयाब हुए। हमें एक पूरे रीक्रॉल साइकल और बहुत सारी कॉफी लगी।
