diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md new file mode 100644 index 000000000000000..367d15586e707c6 --- /dev/null +++ b/docs/advanced-features/i18n-routing.md @@ -0,0 +1,248 @@ +# Internationalized Routing + +
+ Examples + +
+ +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. + +## 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-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', + }, + ], + }, +} +``` + +## 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 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: + +- **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`. + +## Accessing the locale information + +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 currently active locale. +- `locales` contains all configured locales. +- `defaultLocale` contains the configured default locale. + +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 parameter of the function under `locales`. + +## Transition between locales + +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: + +```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 { useRouter } from 'next/router' + +export default function IndexPage(props) { + const router = useRouter() + + return ( +
{ + router.push('/another', '/another', { locale: 'fr' }) + }} + > + to /fr/another +
+ ) +} +``` + +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. + +### Non-dynamic getStaticProps Pages + +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 + +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 +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/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 ceb885896ab7027..2ca3fe32af60993 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 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).