From c220da6ae7f73973b048d0f8b4ac2e61081776de Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 20 Oct 2020 16:06:37 -0500 Subject: [PATCH 1/6] Add initial i18n documentation --- docs/advanced-features/i18n-routing.md | 134 +++++++++++++++++++++++++ docs/basic-features/data-fetching.md | 3 + 2 files changed, 137 insertions(+) create mode 100644 docs/advanced-features/i18n-routing.md diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md new file mode 100644 index 000000000000000..aab7113457611f6 --- /dev/null +++ b/docs/advanced-features/i18n-routing.md @@ -0,0 +1,134 @@ +# i18n (internationalize) Routing + +
+ Examples + +
+ +Next.js has built in support for i18n routing since v9.5.7. With the built-in support you can provide a list of locales you want to support, the default locale, and domain specific locales and Next.js will help handle the routing for these values. + +The i18n routing support is currently meant to compliment existing i18n library solutions like react-intl, react-i18next, lingui, rosetta, and others by streamlining the routes and locale parsing aspects of i18n. + +## How to get started + +To get started you need to add the `i18n` config to your `next.config.js` file. + +```js +module.exports = { + i18n: { + // These are all the locales you want to be able 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-local prefixed path e.g. `/hello` + defaultLocale: 'en-US', + // These are a list of locale domains and the default locale they + // should handle (these are not required) + domains: [ + { + domain: 'example.com', + defaultLocale: 'en-US', + }, + { + domain: 'example.nl', + defaultLocale: 'nl-NL', + }, + { + domain: 'example.fr', + defaultLocale: 'fr', + }, + ], + }, +} +``` + +## How are the routes handled + +Using the above config when a user visits `/` Next.js will automatically try to detect which locale the user prefers with the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header and the current domain. + +If a locale other than the default locale is detected the user will be redirected to either: + +a) the domain with that locale specified as the default +b) the locale prefixed path if no domain matched + +For example, 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. + +If we did not have the `example.fr` domain configured then the user would instead be redirected to `/fr`. + +## Accessing the locale information + +The detected locale information is provided in multiple places to ensure it's available where it might be needed. + +On the `next/router` instance available via the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook we expose the active locale under `router.locale`, all of the supported locales under `router.locales`, and the current default locale under `router.defaultLocale`. + +When prerendering pages with `getStaticProps` the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function as `locale` for the active locale and `locales` for all supported locales. + +When leveraging `getStaticPaths`, the supported locales are also provided in the context provided to the function under `locales`. + +## Transition between locales + +To handle transitioning between locales you can either leverage `next/link` or the `next/router` methods directly. + +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: + +```jsx +import Link from 'next/link' + +export default function IndexPage(props) { + return ( + + To /fr/another + + ) +} +``` + +When using the `next/router` methods directly you can specify the `locale` that should be used via the transition options. For example: + +```jsx +import { useCallback } from 'react' +import { useRouter } from 'next/router' + +export default function IndexPage(props) { + const router = useRouter() + + return ( +
{ + router.push('/another', '/another', { locale: 'fr' }) + }} + > + to /fr/another +
+ ) +} +``` + +## How does this work with static generation + +### Automatically Statically Optimized Pages + +For pages that are automatically statically optimized a version of the page will be generated for each locale. This ensures the `lang` HTML attribute and `router.locale` value have the correct initial values for each locale. + +### Non-dynamic getStaticProps Pages + +For non-dynamic `getStaticProps` pages a version is generated for each locale like above and `getStaticProps` is also called with each `locale` that is being rendered. If you would like to opt-out of a certain locale from being prerendered you can return `notFound: true` from `getStaticProps` and this variant of the page will not be generated. + +### Dynamic getStaticProps Pages + +For dynamic `getStaticProps` pages any locale variants of the page that is desired to be prerendered needs to be returned from [`getStaticPaths`](/docs/basic-features/data-fetching#getstaticpaths-static-generation). Along with the `params` object that can be returned for the `paths` you can now also return a `locale` field specifying which locale you want to render. For example: + +```js +// 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, + } +} +``` diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md index ceb885896ab7027..9923318465ff905 100644 --- a/docs/basic-features/data-fetching.md +++ b/docs/basic-features/data-fetching.md @@ -54,11 +54,14 @@ The `context` parameter is an object containing the following keys: - `params` contains the route parameters for pages using dynamic routes. For example, if the page name is `[id].js` , then `params` will look like `{ id: ... }`. To learn more, take a look at the [Dynamic Routing documentation](/docs/routing/dynamic-routes.md). You should use this together with `getStaticPaths`, which we’ll explain later. - `preview` is `true` if the page is in the preview mode and `undefined` otherwise. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). - `previewData` contains the preview data set by `setPreviewData`. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). +- `locale` contains the active locale (if enabled) +- `locales` contains all supported locales (if enabled) `getStaticProps` should return an object with: - `props` - A **required** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) - `revalidate` - An **optional** amount in seconds after which a page re-generation can occur. More on [Incremental Static Regeneration](#incremental-static-regeneration) +- `notFound` - An **optional** boolean value specifying the page should handle as the 404 page returning the 404 status. More on [Incremental Static Regeneration](#incremental-static-regeneration) > **Note**: You can import modules in top-level scope for use in `getStaticProps`. > Imports used in `getStaticProps` will [not be bundled for the client-side](#write-server-side-code-directly). From 05c0ffe99577c11cbecb335ae25253c90e5dd130 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 21 Oct 2020 11:09:37 -0500 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Tim Neutkens --- docs/advanced-features/i18n-routing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md index aab7113457611f6..cce4311b8e4366f 100644 --- a/docs/advanced-features/i18n-routing.md +++ b/docs/advanced-features/i18n-routing.md @@ -1,4 +1,4 @@ -# i18n (internationalize) Routing +# Internationalized Routing
Examples From 85f2728e531d13619530771770cd2103758ec8be Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Oct 2020 11:46:30 -0500 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Lee Robinson --- docs/advanced-features/i18n-routing.md | 41 +++++++++++++------------- docs/basic-features/data-fetching.md | 4 +-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md index cce4311b8e4366f..6c879ea756ec8cc 100644 --- a/docs/advanced-features/i18n-routing.md +++ b/docs/advanced-features/i18n-routing.md @@ -7,18 +7,18 @@
-Next.js has built in support for i18n routing since v9.5.7. With the built-in support you can provide a list of locales you want to support, the default locale, and domain specific locales and Next.js will help handle the routing for these values. +Next.js has built-in support for internationalized (i18n) routing since `v9.5.7`. 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 compliment existing i18n library solutions like react-intl, react-i18next, lingui, rosetta, and others by streamlining the routes and locale parsing aspects of i18n. +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. -## How to get started +## Getting started -To get started you need to add the `i18n` config to your `next.config.js` file. +To get started, add the `i18n` config to your `next.config.js` file. ```js module.exports = { i18n: { - // These are all the locales you want to be able to support in + // 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 @@ -46,32 +46,32 @@ module.exports = { ## How are the routes handled -Using the above config when a user visits `/` Next.js will automatically try to detect which locale the user prefers with the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header and the current domain. +When a user visits `/`, Next.js will try to automatically detect which locale the user prefers with the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header and the current domain. -If a locale other than the default locale is detected the user will be redirected to either: +If a locale other than the default locale is detected, the user will be redirected to either: -a) the domain with that locale specified as the default -b) the locale prefixed path if no domain matched +A) The domain with that locale specified as the default. +B) The locale prefixed path if no domain matched. -For example, 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. +For example, 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. -If we did not have the `example.fr` domain configured then the user would instead be redirected to `/fr`. +If we did not have the `example.fr` domain configured, then the user would instead be redirected to `/fr`. ## Accessing the locale information The detected locale information is provided in multiple places to ensure it's available where it might be needed. -On the `next/router` instance available via the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook we expose the active locale under `router.locale`, all of the supported locales under `router.locales`, and the current default locale under `router.defaultLocale`. +On the `next/router` instance available via the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook, we expose the active locale under `router.locale`, all of the supported locales under `router.locales`, and the current default locale under `router.defaultLocale`. -When prerendering pages with `getStaticProps` the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function as `locale` for the active locale and `locales` for all supported locales. +When prerendering pages with `getStaticProps`, the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function as `locale` for the active locale and `locales` for all supported locales. When leveraging `getStaticPaths`, the supported locales are also provided in the context provided to the function under `locales`. ## Transition between locales -To handle transitioning between locales you can either leverage `next/link` or the `next/router` methods directly. +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: +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: ```jsx import Link from 'next/link' @@ -85,10 +85,9 @@ export default function IndexPage(props) { } ``` -When using the `next/router` methods directly you can specify the `locale` that should be used via the transition options. For example: +When using the `next/router` methods directly, you can specify the `locale` that should be used via the transition options. For example: ```jsx -import { useCallback } from 'react' import { useRouter } from 'next/router' export default function IndexPage(props) { @@ -106,19 +105,19 @@ export default function IndexPage(props) { } ``` -## How does this work with static generation +## How does this work with static generation? ### Automatically Statically Optimized Pages -For pages that are automatically statically optimized a version of the page will be generated for each locale. This ensures the `lang` HTML attribute and `router.locale` value have the correct initial values for each locale. +For pages that are automatically statically optimized, a version of the page will be generated for each locale. This ensures the `lang` HTML attribute and `router.locale` value have the correct initial values for each locale. ### Non-dynamic getStaticProps Pages -For non-dynamic `getStaticProps` pages a version is generated for each locale like above and `getStaticProps` is also called with each `locale` that is being rendered. If you would like to opt-out of a certain locale from being prerendered you can return `notFound: true` from `getStaticProps` and this variant of the page will not be generated. +For non-dynamic `getStaticProps` pages, a version is generated for each locale like above. `getStaticProps` is also 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. ### Dynamic getStaticProps Pages -For dynamic `getStaticProps` pages any locale variants of the page that is desired to be prerendered needs to be returned from [`getStaticPaths`](/docs/basic-features/data-fetching#getstaticpaths-static-generation). Along with the `params` object that can be returned for the `paths` you can now also return a `locale` field specifying which locale you want to render. For example: +For dynamic `getStaticProps` pages, any locale variants of the page that is desired to be prerendered needs to be returned from [`getStaticPaths`](/docs/basic-features/data-fetching#getstaticpaths-static-generation). 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: ```js // pages/blog/[slug].js diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md index 9923318465ff905..bd2817e58e68c7c 100644 --- a/docs/basic-features/data-fetching.md +++ b/docs/basic-features/data-fetching.md @@ -54,8 +54,8 @@ The `context` parameter is an object containing the following keys: - `params` contains the route parameters for pages using dynamic routes. For example, if the page name is `[id].js` , then `params` will look like `{ id: ... }`. To learn more, take a look at the [Dynamic Routing documentation](/docs/routing/dynamic-routes.md). You should use this together with `getStaticPaths`, which we’ll explain later. - `preview` is `true` if the page is in the preview mode and `undefined` otherwise. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). - `previewData` contains the preview data set by `setPreviewData`. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). -- `locale` contains the active locale (if enabled) -- `locales` contains all supported locales (if enabled) +- `locale` contains the active locale (if enabled). +- `locales` contains all supported locales (if enabled). `getStaticProps` should return an object with: From ba0247c06a6f04cb9e9cc9354aa389f1cb524285 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Oct 2020 11:59:37 -0500 Subject: [PATCH 4/6] Apply more suggestions --- docs/advanced-features/i18n-routing.md | 12 +++++++----- docs/api-reference/next/router.md | 7 ++++++- docs/basic-features/data-fetching.md | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md index 6c879ea756ec8cc..8cd89ec8825a705 100644 --- a/docs/advanced-features/i18n-routing.md +++ b/docs/advanced-features/i18n-routing.md @@ -7,7 +7,7 @@ -Next.js has built-in support for internationalized (i18n) routing since `v9.5.7`. You can provide a list of locales, the default locale, and domain-specific locales and Next.js will automatically handle the routing. +Next.js has built-in support for internationalized ([i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization#Naming)) routing since `v9.5.7`. 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. @@ -59,13 +59,15 @@ If we did not have the `example.fr` domain configured, then the user would inste ## Accessing the locale information -The detected locale information is provided in multiple places to ensure it's available where it might be needed. +On the `next/router` instance available via the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook. It has the following fields: -On the `next/router` instance available via the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook, we expose the active locale under `router.locale`, all of the supported locales under `router.locales`, and the current default locale under `router.defaultLocale`. +- `locale` contains the active locale. +- `locales` contains all supported locales. +- `defaultLocale` contains the current default locale. -When prerendering pages with `getStaticProps`, the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function as `locale` for the active locale and `locales` for all supported locales. +When [prerendering](/docs/basic-features/pages#static-generation-recommended) pages with `getStaticProps`, the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function. -When leveraging `getStaticPaths`, the supported locales are also provided in the context provided to the function under `locales`. +When leveraging `getStaticPaths`, the supported locales are provided in the context provided to the function under `locales`. ## Transition between locales diff --git a/docs/api-reference/next/router.md b/docs/api-reference/next/router.md index 2783c2d324c19f6..30d5a64074b4717 100644 --- a/docs/api-reference/next/router.md +++ b/docs/api-reference/next/router.md @@ -43,7 +43,12 @@ The following is the definition of the `router` object returned by both [`useRou - `pathname`: `String` - Current route. That is the path of the page in `/pages` - `query`: `Object` - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have [data fetching requirements](/docs/basic-features/data-fetching.md). Defaults to `{}` -- `asPath`: `String` - Actual path (including the query) shown in the browser +- `asPath`: `String` - Actual path (including the query) shown in the browser. +- `isFallback`: `boolean` - Whether the current page is in [fallback mode](/docs/basic-features/data-fetching#fallback-pages). +- `basePath`: `String` - The active [basePath](/docs/api-reference/next.config.js/basepath) (if enabled). +- `locale`: `String` - The active locale (if enabled). +- `locales`: `String[]` - All supported locales (if enabled). +- `defaultLocale`: `String` - The current default locale (if enabled). Additionally, the following methods are also included inside `router`: diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md index bd2817e58e68c7c..60bfd3992e8b8d5 100644 --- a/docs/basic-features/data-fetching.md +++ b/docs/basic-features/data-fetching.md @@ -61,7 +61,7 @@ The `context` parameter is an object containing the following keys: - `props` - A **required** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) - `revalidate` - An **optional** amount in seconds after which a page re-generation can occur. More on [Incremental Static Regeneration](#incremental-static-regeneration) -- `notFound` - An **optional** boolean value specifying the page should handle as the 404 page returning the 404 status. More on [Incremental Static Regeneration](#incremental-static-regeneration) +- `notFound` - An **optional** boolean value specifying the page should render the 404 page with a 404 status code. More on [Incremental Static Regeneration](#incremental-static-regeneration) > **Note**: You can import modules in top-level scope for use in `getStaticProps`. > Imports used in `getStaticProps` will [not be bundled for the client-side](#write-server-side-code-directly). From 43d53f588bc089b032c67338449520b986857eb8 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 22 Oct 2020 13:09:01 -0500 Subject: [PATCH 5/6] rephrase a bit more --- docs/basic-features/data-fetching.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md index 60bfd3992e8b8d5..2ca3fe32af60993 100644 --- a/docs/basic-features/data-fetching.md +++ b/docs/basic-features/data-fetching.md @@ -61,7 +61,7 @@ The `context` parameter is an object containing the following keys: - `props` - A **required** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) - `revalidate` - An **optional** amount in seconds after which a page re-generation can occur. More on [Incremental Static Regeneration](#incremental-static-regeneration) -- `notFound` - An **optional** boolean value specifying the page should render the 404 page with a 404 status code. More on [Incremental Static Regeneration](#incremental-static-regeneration) +- `notFound` - An optional boolean value to allow the page to return a 404 status and page. More on [Incremental Static Regeneration](#incremental-static-regeneration) > **Note**: You can import modules in top-level scope for use in `getStaticProps`. > Imports used in `getStaticProps` will [not be bundled for the client-side](#write-server-side-code-directly). From 053d2a95f88d179c22ead2d49e3400192657d2f4 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 23 Oct 2020 11:48:27 +0200 Subject: [PATCH 6/6] Update doc --- docs/advanced-features/i18n-routing.md | 153 +++++++++++++++++++++---- 1 file changed, 133 insertions(+), 20 deletions(-) diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md index 8cd89ec8825a705..367d15586e707c6 100644 --- a/docs/advanced-features/i18n-routing.md +++ b/docs/advanced-features/i18n-routing.md @@ -7,25 +7,34 @@ -Next.js has built-in support for internationalized ([i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization#Naming)) routing since `v9.5.7`. You can provide a list of locales, the default locale, and domain-specific locales and Next.js will automatically handle the routing. +Next.js has built-in support for internationalized ([i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization#Naming)) 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. +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. ## Getting started To get started, add the `i18n` config to your `next.config.js` file. +Locales are [UTS Locale Identifiers](https://www.unicode.org/reports/tr35/tr35-59/tr35.html#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 States +- `nl-NL` - Dutch as spoken in the Netherlands +- `nl` - Dutch, no specific region + ```js +// 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-local prefixed path e.g. `/hello` + // a non-locale prefixed path e.g. `/hello` defaultLocale: 'en-US', - // These are a list of locale domains and the default locale they - // should handle (these are not required) + // 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', @@ -44,30 +53,91 @@ module.exports = { } ``` -## How are the routes handled +## Locale Strategies + +There are two locale handling strategies: Sub-path Routing and Domain Routing. + +### Sub-path Routing + +Sub-path Routing puts the locale in the url path. + +```js +// 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. + +### Domain Routing + +By using domain routing you can configure locales to be served from different domains: + +```js +// 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` + +## Automatic Locale Detection -When a user visits `/`, Next.js will try to automatically detect which locale the user prefers with the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header and the current domain. +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`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header and the current domain. If a locale other than the default locale is detected, the user will be redirected to either: -A) The domain with that locale specified as the default. -B) The locale prefixed path if no domain matched. +- **When using Sub-path Routing:** The locale prefixed path +- **When using Domain Routing:** The domain with that locale specified as the default -For example, 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 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. -If we did not have the `example.fr` domain configured, then the user would instead be redirected to `/fr`. +When using Sub-path Routing, the user would be redirected to `/fr`. ## Accessing the locale information -On the `next/router` instance available via the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook. It has the following fields: +You can access the locale information via the Next.js router. For example, using the [`useRouter()`](https://nextjs.org/docs/api-reference/next/router#userouter) hook the following properties are available: -- `locale` contains the active locale. -- `locales` contains all supported locales. -- `defaultLocale` contains the current default locale. +- `locale` contains the currently active locale. +- `locales` contains all configured locales. +- `defaultLocale` contains the configured default locale. -When [prerendering](/docs/basic-features/pages#static-generation-recommended) pages with `getStaticProps`, the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function. +When [pre-rendering](/docs/basic-features/pages#static-generation-recommended) pages with `getStaticProps` or `getServerSideProps`, the locale information is provided in [the context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) provided to the function. -When leveraging `getStaticPaths`, the supported locales are provided in the context provided to the function under `locales`. +When leveraging `getStaticPaths`, the supported locales are provided in the context parameter of the function under `locales`. ## Transition between locales @@ -107,15 +177,58 @@ export default function IndexPage(props) { } ``` -## How does this work with static generation? +If you have a `href` that already includes the locale you can opt-out of automatically handling the locale prefixing: + +```jsx +import Link from 'next/link' + +export default function IndexPage(props) { + return ( + + To /fr/another + + ) +} +``` + +## Search Engine Optimization + +Since Next.js knows what language the user is visiting it will automatically add the `lang` attribute to the `` 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`](/docs/api-reference/next/head.md). You can learn more about `hreflang` in the [Google Webmasters documentation](https://support.google.com/webmasters/answer/189077). + +## How does this work with Static Generation? ### Automatically Statically Optimized Pages -For pages that are automatically statically optimized, a version of the page will be generated for each locale. This ensures the `lang` HTML attribute and `router.locale` value have the correct initial values for each locale. +For pages that are automatically statically optimized, a version of the page will be generated for each locale. ### Non-dynamic getStaticProps Pages -For non-dynamic `getStaticProps` pages, a version is generated for each locale like above. `getStaticProps` is also 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. +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. + +```js +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, + }, + } +} +``` ### Dynamic getStaticProps Pages