Skip to content

Commit

Permalink
docs: Various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
amannn committed Nov 14, 2023
1 parent f542802 commit c7b2626
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ import {getTranslations} from 'next-intl/server';
const locale = params.locale;

// This creates the same function that is returned by `useTranslations`.
const t = await getTranslations(locale);
const t = await getTranslations({locale});

// Result: "Hello world!"
t('hello', {name: 'world'});
Expand Down
3 changes: 2 additions & 1 deletion docs/pages/docs/environments/error-files.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function CatchAllPage() {
}
```

After this change, all requests that are matched within the `[locale]` segment will render the `not-found` page when an unknown route is encountered.
After this change, all requests that are matched within the `[locale]` segment will render the `not-found` page when an unknown route is encountered (e.g. `/en/unknown`).

### Catching non-localized requests

Expand All @@ -54,6 +54,7 @@ You can add a root `not-found` page to handle these cases too.

import {redirect, usePathname} from 'next/navigation';

// Can be imported from a shared config
const defaultLocale = 'en';

export default function NotFound() {
Expand Down
6 changes: 6 additions & 0 deletions docs/pages/docs/environments/metadata-route-handlers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export async function generateMetadata({params: {locale}}) {
}
```

<Callout>
By passing an explicit `locale` to the awaitable functions from `next-intl`,
you can make the metadata handler eligable for [static
rendering](/docs/getting-started/app-router#static-rendering).
</Callout>

### Metadata files

If you need to internationalize content within [metadata files](https://nextjs.org/docs/app/api-reference/file-conventions/metadata), such as an Open Graph image, you can call APIs from `next-intl` in the exported function.
Expand Down
4 changes: 3 additions & 1 deletion docs/pages/docs/environments/server-client-components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ The one restriction that currently comes with this pattern is that hooks can not
<details>
<summary>Should I use async or non-async functions for my components?</summary>

If you implement components that qualify as shared components, it can be beneficial to implement them as non-async functions. This allows to use these components either in a server or client environment, making them really flexible. Even if you don't intend to to ever run a particular component on the client side, this compatibility can still be helpful, e.g. for simplified testing. However, there's no need to dogmatically use non-async functions exclusively for handling internationalization—use what fits your app best.
If you implement components that qualify as shared components, it can be beneficial to implement them as non-async functions. This allows to use these components either in a server or client environment, making them really flexible. Even if you don't intend to to ever run a particular component on the client side, this compatibility can still be helpful, e.g. for simplified testing.

However, there's no need to dogmatically use non-async functions exclusively for handling internationalization—use what fits your app best.

</details>

Expand Down
25 changes: 13 additions & 12 deletions docs/pages/docs/getting-started/app-router.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ The Next.js App Router introduces support for [React Server Components](https://

## Getting started

If you haven't done so already, [create a Next.js app that uses the App Router](https://nextjs.org/docs/getting-started/installation). All pages should be moved within a `[locale]` folder so that we can use this segment to provide content in different languages (e.g. `/en`, `/en/about`, etc.).
If you haven't done so already, [create a Next.js app that uses the App Router](https://nextjs.org/docs/getting-started/installation).

**Start by running `npm install next-intl` and create the following file structure:**
`next-intl` integrates with the App Router, by using a `[locale]` [dynamic segment](https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes) so that we can use this segment to provide content in different languages (e.g. `/en`, `/en/about`, etc.).

Let's get started!

**Run `npm install next-intl` and create the following file structure:**

```
├── messages (1)
Expand Down Expand Up @@ -45,7 +49,7 @@ The simplest option is to add JSON files in your project based on locales, e.g.

### `next.config.js`

Now, set up the plugin which provides i18n configuration for Server Components.
Now, set up the plugin which creates an alias to import your i18n configuration (specified in the next step) into Server Components.

```js filename="next.config.js"
const withNextIntl = require('next-intl/plugin')();
Expand Down Expand Up @@ -89,7 +93,7 @@ module.exports = withNextIntl({

### `middleware.ts`

[The middleware](/docs/routing/middleware) matches a locale for the request and handles redirects and rewrites accordingly.
The middleware matches a locale for the request and handles redirects and rewrites accordingly.

```tsx filename="middleware.ts"
import createMiddleware from 'next-intl/middleware';
Expand All @@ -115,6 +119,7 @@ The `locale` that was matched by the middleware is available via the `locale` pa
```tsx filename="app/[locale]/layout.tsx"
import {notFound} from 'next/navigation';

// Can be imported from a shared config
const locales = ['en', 'de'];

export default function LocaleLayout({children, params: {locale}}) {
Expand Down Expand Up @@ -166,12 +171,8 @@ That's all it takes!
navigation docs](/docs/routing/navigation).
</li>
<li>
Wondering how to link between internationalized pages? Have a look at [the
navigation docs](/docs/routing/navigation).
</li>
<li>
Are you transitioning from the Pages Router to the App Router? Check out the
migration example.
Are you transitioning from the Pages to the App Router? Check out [the
migration example](/examples/app-router-migration).
</li>
</ul>

Expand Down Expand Up @@ -240,13 +241,13 @@ export default function IndexPage({

**Important:** `unstable_setRequestLocale` needs to be called after the `locale` is validated, but before you call any hooks from `next-intl`. Otherwise, you'll get an error when trying to prerender the page.

Note that Next.js can render layouts and pages indepently. This means that e.g. when you navigate from `/settings/profile` to `/settings/privacy`, the `/settings` segment might not re-render as part of the request. Due to this, it's important that `unstable_setRequestLocale` is called not only in the parent `settings/layout.tsx`, but also in the individual pages `profile/page.tsx` and `privacy/page.tsx`.

<details>
<summary>What does "unstable" mean?</summary>

`unstable_setRequestLocale` is meant to be used as a stopgap solution and we aim to remove it in the future [in case Next.js adds an API to access parts of the URL](https://github.com/facebook/react/pull/27424#issuecomment-1739464985). If that's the case, you'll get a deprecation notice in a minor version and the API will be removed as part of a major version.

Note that Next.js can render layouts and pages indepently. This means that e.g. when you navigate from `/settings/profile` to `/settings/privacy`, the `/settings` segment might not re-render as part of the request. Due to this, it's important that `unstable_setRequestLocale` is called not only in the parent `settings/layout.tsx`, but also in the individual pages `profile/page.tsx` and `privacy/page.tsx`.

That being said, the API is expected to work reliably if you're cautious to apply it in all relevant places.

</details>
Expand Down
79 changes: 32 additions & 47 deletions docs/pages/docs/usage/messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ The main part of handling internationalization (typically referred to as _i18n_)

## Terminology

- **Locale**: We use this term to describe an identifier that contains the language and formatting preferences of users. Apart from the language, this includes optional regional information (e.g. `en-US`).
- **Messages**: These are collections of namespace-label pairs that provide grouping by locale (e.g. `en-US.json`).
- **Locale**: We use this term to describe an identifier that contains the language and formatting preferences of users. Apart from the language, a locale can include optional regional information (e.g. `en-US`). Locales are specified as [IETF BCP 47 language tags](https://en.wikipedia.org/wiki/IETF_language_tag).
- **Messages**: These are collections of namespace-label pairs that are grouped by locale (e.g. `en-US.json`).

## Structuring messages

To group your messages within a locale, it's recommended to use component names as namespaces and embrace them as the primary unit of code organization in your app.
To group your messages within a locale, it's recommended to use component names as namespaces and embrace them as the primary unit of code organization in your app. You can of course also use a different structure, depending on what suits your app best.

```json filename="en.json"
{
Expand All @@ -22,9 +22,9 @@ To group your messages within a locale, it's recommended to use component names
}
```

Now, you can render messages from within a React component via the `useTranslations` hook:
You can render messages from within a React component via the `useTranslations` hook:

```js filename="About.tsx"
```tsx filename="About.tsx"
import {useTranslations} from 'next-intl';

function About() {
Expand Down Expand Up @@ -60,7 +60,7 @@ Optionally, you can structure your messages as nested objects.
}
```

```js filename="SignUp.tsx"
```tsx filename="SignUp.tsx"
import {useTranslations} from 'next-intl';

function SignUp() {
Expand Down Expand Up @@ -117,9 +117,7 @@ export default function useLocaleLabel() {
<details>
<summary>How can I use translations outside of components?</summary>

`next-intl` is heavily based on the `useTranslations` API which is intended to consume translations from within React components.

This may seem like an unnecessary limitation, but this is intentional and aims to encourage the use of proven patterns that avoid potential issues—especially if they are easy to overlook.
`next-intl` is heavily based on the `useTranslations` API which is intended to consume translations from within React components. This may seem like a limitation, but this is intentional and aims to encourage the use of proven patterns that avoid potential issues—especially if they are easy to overlook.

If you're interested to dive deeper into this topic, there's a blog post that discusses the background of this design decision: [How (not) to use translations outside of React components](/blog/translations-outside-of-react-components).

Expand Down Expand Up @@ -203,7 +201,7 @@ To match a specific number, `next-intl` additionally supports the special `=valu

To apply pluralization based on an order of items, the `selectordinal` argument can be used:

```js filename="en.json"
```tsx filename="en.json"
"message": "It's your {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} birthday!"
```

Expand Down Expand Up @@ -235,7 +233,7 @@ To match a specific number, `next-intl` additionally supports the special `=valu

To map identifiers to human readable labels, you can use the `select` argument:

```js filename="en.json"
```tsx filename="en.json"
"message": "{gender, select, female {She} male {He} other {They}} is online."
```

Expand Down Expand Up @@ -296,7 +294,7 @@ Messages can use tags without any chunks as children, but syntax-wise, a closing

```js
t.rich('message', {
br: (chunks) => <br />
br: () => <br />
});
```

Expand Down Expand Up @@ -385,56 +383,43 @@ If you need to render a list of messages, the recommended approach is to map an

```json filename="en.json"
{
"Benefits": {
"zero-config": "Works with zero config",
"customizable": "Easy to customize",
"fast": "Blazingly fast"
"CompanyStats": {
"yearsOfService": {
"title": "Years of service",
"value": "34"
},
"happyClients": {
"title": "Happy clients",
"value": "1.000+"
},
"partners": {
"title": "Products",
"value": "5.000+"
}
}
}
```

```js filename="Benefits.tsx"
```tsx filename="CompanyStats.tsx"
import {useTranslations} from 'next-intl';

function Benefits() {
const t = useTranslations('Benefits');
const keys = ['zero-config', 'customizable', 'fast'] as const;
function CompanyStats() {
const t = useTranslations('CompanyStats');
const keys = ['yearsOfService', 'happyClients', 'partners'] as const;

return (
<ul>
{keys.map((key) => (
<li key={key}>{t(key)}</li>
<li key={key}>
<h2>{t(`${key}.title`)}</h2>
<p>{t(`${key}.value`)}</p>
</li>
))}
</ul>
);
}
```

If the number of items varies between locales, you can solve this by using [rich text](#rich-text).

```json filename="en.json"
{
"Benefits": {
"items": "<item>Works with zero config</item><item>Easy to customize</item><item>Blazingly fast</item>"
}
}
```

```js filename="Benefits.tsx"
import {useTranslations} from 'next-intl';

function Benefits() {
const t = useTranslations('Benefits');
return (
<ul>
{t.rich('items', {
item: (chunks) => <li>{chunks}</li>
})}
</ul>
);
}
```

<details>
<summary>Why can't I just use arrays in my messages?</summary>

Expand All @@ -450,7 +435,7 @@ The advantage of this approach over supporting arrays in messages is that this w
}
```

```js filename="Benefits.tsx"
```tsx filename="Benefits.tsx"
import {useTranslations} from 'next-intl';

function Benefits() {
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/examples/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"title": "Pages Router",
"theme": {"layout": "full"}
},
"pages-router-advanced": {
"title": "Pages Router (advanced)",
"app-router-migration": {
"title": "App Router migration",
"theme": {"layout": "full"}
}
}
11 changes: 0 additions & 11 deletions docs/pages/examples/pages-router-advanced.mdx

This file was deleted.

0 comments on commit c7b2626

Please sign in to comment.