Lost in Translation? App Router i18n Setups That Don't Break SEO
Why SEO-Friendly i18n is Non-Negotiable
The Dangers of Duplicate Content
Signaling Language and Region to Google
The User Experience Factor
The Best Practice: Locale in the URL Path
Why Path-Based Routing Wins
Introducing the [locale] Dynamic Segment
Implementing i18n with next-intl
Installation and Configuration
Creating the Middleware
Structuring Translation Files
Translating Your Content: Server and Client Components
Translating in Server Components with useTranslations
Handling Client Components with Providers
Building a Language Switcher
The SEO Gold Standard: Metadata and hreflang
Dynamic Titles and Descriptions with generateMetadata
Generating hreflang Links Automatically
Setting the lang Attribute
Conclusion
References
/about
. French speakers see French content at... /about
. Same URL, different content./about
. Later, it crawls again from a different location and sees French content at the same URL. The algorithm scratches its digital head. Is this duplicate content? Which version should it index? Often, it picks one randomly and ignores the others.hreflang
tags - your multilingual site's best friend. These HTML attributes tell search engines exactly which language and region each page targets. They're like little signs saying "Hey Google, this page is for French speakers in Canada" or "This one's for Spanish speakers everywhere."hreflang
tags, search engines play a guessing game. They might look at your content and try to detect the language. They might check your server location. But why leave it to chance? Clear signals mean your French content appears for French searches, your German content for German searches, and so on.hreflang
is that it creates connections between translated versions of the same page. Google understands that /en/about
and /fr/a-propos
are the same content in different languages. It can then serve the right version to the right user based on their language preferences and location.yoursite.com/blog/article
. Her friend clicks it and lands on the English version because their browser is set to English. Confusion ensues.yoursite.com/es/blog/articulo
. Her friend immediately sees it's the Spanish version. They click and get exactly what they expect. Trust builds. Engagement increases./de/
in the URL and know they're getting German content. They can bookmark language-specific pages. They can share them on social media without worrying about language confusion. All these positive user signals feed back into better SEO performance.example.fr
, example.de
). You could use subdomains (fr.example.com
, de.example.com
). Or you could use path segments (example.com/fr
, example.com/de
).example.de
is really your site.[locale]
Dynamic Segmentapp
directory, you create a dynamic segment called [locale]
. This becomes the foundation of your entire internationalization strategy.[locale]
folder is a dynamic route segment. When users visit /en/about
, Next.js knows that locale = 'en'
. When they visit /fr/about
, locale = 'fr'
. This parameter becomes available throughout your app, letting you load the right translations, generate the correct metadata, and build language-aware features.[locale]
folder.next-intl
next-intl
has become the go-to library for Next.js App Router internationalization. It handles the heavy lifting while giving you flexibility where you need it.next-intl
takes just a few minutes. First, install the package:i18n.config.ts
file in your project root:i18n.ts
file to handle message loading:next-intl
where to find your translation files. When a user visits /fr/about
, it loads messages from /messages/fr.json
. Simple and predictable.middleware.ts
file in your project root:Accept-Language
header to detect user preferences. It validates that the requested locale actually exists. And it handles redirects - if someone visits /about
, it redirects them to /en/about
(or their preferred language).localePrefix: 'always'
setting ensures every page has a locale in its URL. This consistency is crucial for SEO - search engines always see clear, unambiguous URLs for each language version.messages
folder in your project root with JSON files for each locale:useTranslations
useTranslations
hook loads only the translations you need. In this example, it loads the 'about' section from your messages file. This keeps your component bundles lean and improves performance.useTranslations
hook directly. Instead, you pass messages down from a Server Component parent.hreflang
hreflang
implementation can make the difference between ranking well globally or disappearing into search engine obscurity.generateMetadata
generateMetadata
function makes this dynamic generation clean and efficient.hreflang
Links Automaticallyhreflang
tags tell search engines about all language versions of a page. Miss one, and you're leaving SEO value on the table.hreflang
tags across hundreds of pages is a recipe for errors. Instead, generate them dynamically:hreflang
links for all your supported languages. Search engines see the connections between translated pages and can serve the right version to each user.x-default
tag for users whose language you don't support:lang
Attributelang
attribute on your HTML tag might seem minor, but it's a crucial accessibility and SEO signal. Screen readers use it to pronounce content correctly. Search engines use it as another language indicator.hreflang
implementation - your international content can thrive in search results across the globe.Posted Jun 19, 2025
Go global without sacrificing your rank. Learn how to implement SEO-friendly internationalization (i18n) in the Next.js App Router using best practices.