Examples
Next.js has built-in support for internationalized (i18n) routing since v10.0.0
. You can provide a list of locales, the default locale, and domain-specific locales and Next.js will automatically handle the routing.
The i18n routing support is currently meant to complement existing i18n library solutions like react-intl
, react-i18next
, lingui
, rosetta
, and others by streamlining the routes and locale parsing.
To get started, add the i18n
config to your next.config.js
file.
Locales are UTS Locale Identifiers, a standardized format for defining locales.
Generally a Locale Identifier is made up of a language, region, and script separated by a dash: language-region-script
. The region and script are optional. An example:
en-US
- English as spoken in the United Statesnl-NL
- Dutch as spoken in the Netherlandsnl
- Dutch, no specific region
// next.config.js
module.exports = {
i18n: {
// These are all the locales you want to support in
// your application
locales: ['en-US', 'fr', 'nl-NL'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'en-US',
// This is a list of locale domains and the default locale they
// should handle (these are only required when setting up domain routing)
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
],
},
}
There are two locale handling strategies: Sub-path Routing and Domain Routing.
Sub-path Routing puts the locale in the url path.
// next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
},
}
With the above configuration en-US
, fr
, and nl-NL
will be available to be routed to, and en-US
is the default locale. If you have a pages/blog.js
the following urls would be available:
/blog
/fr/blog
/nl-nl/blog
The default locale does not have a prefix.
By using domain routing you can configure locales to be served from different domains:
// next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
},
],
},
}
For example if you have pages/blog.js
the following urls will be available:
example.com/blog
example.fr/blog
example.nl/blog
When a user visits the application root (generally /
), Next.js will try to automatically detect which locale the user prefers based on the Accept-Language
header and the current domain.
If a locale other than the default locale is detected, the user will be redirected to either:
- When using Sub-path Routing: The locale prefixed path
- When using Domain Routing: The domain with that locale specified as the default
When using Domain Routing, if a user with the Accept-Language
header fr;q=0.9
visits example.com
, they will be redirected to example.fr
since that domain handles the fr
locale by default.
When using Sub-path Routing, the user would be redirected to /fr
.
You can access the locale information via the Next.js router. For example, using the useRouter()
hook the following properties are available:
locale
contains the currently active locale.locales
contains all configured locales.defaultLocale
contains the configured default locale.
When pre-rendering pages with getStaticProps
or getServerSideProps
, the locale information is provided in the context provided to the function.
When leveraging getStaticPaths
, the configured locales are provided in the context parameter of the function under locales
and the configured defaultLocale under defaultLocale
.
You can use next/link
or next/router
to transition between locales.
For next/link
, a locale
prop can be provided to transition to a different locale from the currently active one. If no locale
prop is provided, the currently active locale
is used during client-transitions. For example:
import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/another" locale="fr">
<a>To /fr/another</a>
</Link>
)
}
When using the next/router
methods directly, you can specify the locale
that should be used via the transition options. For example:
import { useRouter } from 'next/router'
export default function IndexPage(props) {
const router = useRouter()
return (
<div
onClick={() => {
router.push('/another', '/another', { locale: 'fr' })
}}
>
to /fr/another
</div>
)
}
If you have a href
that already includes the locale you can opt-out of automatically handling the locale prefixing:
import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/fr/another" locale={false}>
<a>To /fr/another</a>
</Link>
)
}
Since Next.js knows what language the user is visiting it will automatically add the lang
attribute to the <html>
tag.
Next.js doesn't know about variants of a page so it's up to you to add the hreflang
meta tags using next/head
. You can learn more about hreflang
in the Google Webmasters documentation.
For pages that are automatically statically optimized, a version of the page will be generated for each locale.
For non-dynamic getStaticProps
pages, a version is generated for each locale like above. getStaticProps
is called with each locale
that is being rendered. If you would like to opt-out of a certain locale from being pre-rendered, you can return notFound: true
from getStaticProps
and this variant of the page will not be generated.
export async function getStaticProps({ locale }) {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch(`https://.../posts?locale=${locale}`)
const posts = await res.json()
if (posts.length === 0) {
return {
notFound: true,
}
}
// By returning { props: posts }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
For dynamic getStaticProps
pages, any locale variants of the page that is desired to be prerendered needs to be returned from getStaticPaths
. Along with the params
object that can be returned for the paths
, you can also return a locale
field specifying which locale you want to render. For example:
// pages/blog/[slug].js
export const getStaticPaths = ({ locales }) => {
return {
paths: [
{ params: { slug: 'post-1' }, locale: 'en-US' },
{ params: { slug: 'post-1' }, locale: 'fr' },
],
fallback: true,
}
}