Skip to content

Commit e1ac008

Browse files
docs: Explain passing rich text functions in defaultTranslationMessages to NextIntlClientProvider (#878 by @janoschherrmann)
Closes #865 --------- Co-authored-by: Jan Amann <jan@amann.me>
1 parent e0294ae commit e1ac008

File tree

5 files changed

+39
-24
lines changed

5 files changed

+39
-24
lines changed

docs/pages/docs/usage/configuration.mdx

+31-4
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ function Component() {
380380

381381
## Default translation values
382382

383-
To achieve consistent usage of translation values and reduce redundancy, you can define a set of global default values. This configuration can also be used to apply consistent styling of commonly used rich text elements.
383+
To achieve consistent usage of translation values and reduce redundancy, you can define a set of global default values. This configuration can also be used to apply consistent styling of commonly used rich text elements. In case you provide values at a specific call site of `t`, these will potentially override global defaults.
384384

385385
<Tabs items={['i18n.ts', 'Provider']}>
386386
<Tab>
@@ -414,11 +414,38 @@ export default getRequestConfig(async ({locale}) => {
414414
</NextIntlClientProvider>
415415
```
416416

417+
Note that `NextIntlClientProvider` is a Client Component, therefore if you render it from a Server Component, the props need to be [serializable](https://react.dev/reference/react/use-client#serializable-types) across the server/client boundary.
418+
419+
If you provide rich text element functions, this means that you should render the provider along with the configuration for `defaultTranslationValues` from a component that is marked with `'use client'`:
420+
421+
```tsx filename="Provider.tsx"
422+
// Making this a Client Component allows us to provide
423+
// non-serializable props to `NextIntlClientProvider`
424+
'use client';
425+
426+
import {NextIntlClientProvider} from 'next-intl';
427+
428+
export default function Provider({messages, children}) {
429+
return (
430+
<NextIntlClientProvider
431+
// Passing functions as props is fine here!
432+
defaultTranslationValues={{
433+
important: (chunks) => <b>{chunks}</b>
434+
}}
435+
// Forward messages from the server side
436+
messages={messages}
437+
>
438+
{children}
439+
</NextIntlClientProvider>
440+
);
441+
}
442+
```
443+
444+
In this case, `messages` should be provided from a Server Component, potentially as returned from the [`useMessages`](/docs/usage/configuration#messages) hook.
445+
417446
</Tab>
418447
</Tabs>
419448

420-
The defaults will be overridden if local formats are provided at a specific call site.
421-
422449
## Error handling
423450

424451
By default, when a message fails to resolve or when the formatting failed, an error will be printed on the console. In this case `${namespace}.${key}` will be rendered instead to keep your app running.
@@ -456,7 +483,7 @@ export default getRequestConfig(async ({locale}) => {
456483
}
457484
};
458485
});
459-
````
486+
```
460487

461488
</Tab>
462489
<Tab>

docs/theme.config.tsx

-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import Footer from 'components/Footer';
22
import PartnerSidebar from 'components/PartnerSidebar';
3-
import Link from 'next/link';
43
import {useRouter} from 'next/router';
54
import {ThemeConfig} from 'nextra';
65
import {Navbar, ThemeSwitch, useConfig} from 'nextra-theme-docs';
@@ -83,17 +82,6 @@ export default {
8382
titleTemplate: '%s – Internationalization (i18n) for Next.js'
8483
};
8584
},
86-
banner: {
87-
text: (
88-
<>
89-
next-intl 3.0 is out! (
90-
<Link className="underline" href="/blog/next-intl-3-0">
91-
announcement
92-
</Link>
93-
)
94-
</>
95-
)
96-
},
9785
primaryHue: {light: 210, dark: 195},
9886
footer: {
9987
component: Footer

packages/next-intl/src/react-server/NextIntlClientProvider.tsx packages/next-intl/src/react-server/NextIntlClientProviderServer.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import BaseNextIntlClientProvider from '../shared/NextIntlClientProvider';
44

55
type Props = ComponentProps<typeof BaseNextIntlClientProvider>;
66

7-
export default async function NextIntlClientProvider({
7+
export default async function NextIntlClientProviderServer({
88
locale,
99
now,
1010
timeZone,

packages/next-intl/src/react-server/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export {default as useFormatter} from './useFormatter';
1313
export {default as useNow} from './useNow';
1414
export {default as useTimeZone} from './useTimeZone';
1515
export {default as useMessages} from './useMessages';
16-
export {default as NextIntlClientProvider} from './NextIntlClientProvider';
16+
export {default as NextIntlClientProvider} from './NextIntlClientProviderServer';
1717

1818
// Everything from `core`
1919
export * from 'use-intl/core';

packages/next-intl/test/react-server/NextIntlClientProvider.test.tsx packages/next-intl/test/react-server/NextIntlClientProviderServer.test.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {expect, it, vi} from 'vitest';
2-
import NextIntlClientProvider from '../../src/react-server/NextIntlClientProvider';
2+
import NextIntlClientProviderServer from '../../src/react-server/NextIntlClientProviderServer';
33
import {getLocale, getNow, getTimeZone} from '../../src/server.react-server';
4-
import BaseNextIntlClientProvider from '../../src/shared/NextIntlClientProvider';
4+
import NextIntlClientProvider from '../../src/shared/NextIntlClientProvider';
55

66
vi.mock('../../src/server/react-server', async () => ({
77
getLocale: vi.fn(async () => 'en-US'),
@@ -14,14 +14,14 @@ vi.mock('../../src/shared/NextIntlClientProvider', async () => ({
1414
}));
1515

1616
it("doesn't read from headers if all relevant configuration is passed", async () => {
17-
const result = await NextIntlClientProvider({
17+
const result = await NextIntlClientProviderServer({
1818
children: null,
1919
locale: 'en-GB',
2020
now: new Date('2020-02-01T00:00:00.000Z'),
2121
timeZone: 'Europe/London'
2222
});
2323

24-
expect(result.type).toBe(BaseNextIntlClientProvider);
24+
expect(result.type).toBe(NextIntlClientProvider);
2525
expect(result.props).toEqual({
2626
children: null,
2727
locale: 'en-GB',
@@ -35,11 +35,11 @@ it("doesn't read from headers if all relevant configuration is passed", async ()
3535
});
3636

3737
it('reads missing configuration from getter functions', async () => {
38-
const result = await NextIntlClientProvider({
38+
const result = await NextIntlClientProviderServer({
3939
children: null
4040
});
4141

42-
expect(result.type).toBe(BaseNextIntlClientProvider);
42+
expect(result.type).toBe(NextIntlClientProvider);
4343
expect(result.props).toEqual({
4444
children: null,
4545
locale: 'en-US',

0 commit comments

Comments
 (0)