Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Deprecate defaultTranslationValues #1411

Merged
merged 5 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/pages/docs/usage/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,12 @@ function Component() {
}
```

## Default translation values
## Default translation values (deprecated) [#default-translation-values]

<Callout>
This feature is deprecated and will be removed in the next major version of `next-intl` ([alternative](/docs/usage/messages#rich-text-reuse-tags)).

</Callout>

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.

Expand Down
43 changes: 40 additions & 3 deletions docs/pages/docs/usage/messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ t('message'); // "Escape curly braces with single quotes (e.g. {name})"

## Rich text

You can format rich text with custom tags and map them to React components:
You can format rich text with custom tags and map them to React components via `t.rich`:

```json filename="en.json"
{
Expand All @@ -351,9 +351,46 @@ t.rich('message', {
Tags can be arbitrarily nested (e.g. `This is <important><very>very</very> important</important>`).

<Details id="rich-text-reuse-tags">
<summary>How can I reuse a tag across my app?</summary>
<summary>How can I reuse tags across my app?</summary>

If you want to use the same tag across your app, you can configure it via [default translation values](/docs/usage/configuration#default-translation-values).
Common tags for rich text that you want to share across your app can be defined in a shared module and imported where relevant for usage with `t.rich`.

A convenient pattern is to use a component that provides common tags via a render prop:

```js
import {useTranslations} from 'next-intl';
import RichText from '@/components/RichText';

function AboutPage() {
const t = useTranslations('AboutPage');
return <RichText>{(tags) => t.rich('description', tags)}</RichText>;
}
```

In this case, the `RichText` component can provide styled tags and also a general layout for the text:

```js filename="components/RichText.tsx"
import {ReactNode} from 'react';

// These tags are available
type Tag = 'p' | 'b' | 'i';

type Props = {
children(tags: Record<Tag, (chunks: ReactNode) => ReactNode>): ReactNode
};

export default function RichText({children}: Props) {
return (
<div className="prose">
{children({
p: (chunks: ReactNode) => <p>{chunks}</p>,
b: (chunks: ReactNode) => <b className="font-semibold">{chunks}</b>,
i: (chunks: ReactNode) => <i className="italic">{chunks}</i>
})}
</div>
);
}
```

</Details>

Expand Down
5 changes: 2 additions & 3 deletions examples/example-app-router-playground/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
},
"AsyncComponent": {
"basic": "AsyncComponent",
"markup": "Markup with <b>{globalString}</b>",
"markup": "Markup with <important>bold content</important>",
"rich": "This is a <important>rich</important> text."
},
"Client": {
Expand All @@ -21,8 +21,7 @@
},
"Index": {
"description": "Das ist die Startseite.",
"globalDefaults": "<highlight>{globalString}</highlight>",
"rich": "Das ist <important>formatierter</important> Test.",
"rich": "Das ist <b>formatierter</b> Test.",
"title": "Start"
},
"JustIn": {
Expand Down
5 changes: 2 additions & 3 deletions examples/example-app-router-playground/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
},
"AsyncComponent": {
"basic": "AsyncComponent",
"markup": "Markup with <b>{globalString}</b>",
"markup": "Markup with <important>bold content</important>",
"rich": "This is a <important>rich</important> text."
},
"Client": {
Expand All @@ -21,8 +21,7 @@
},
"Index": {
"description": "This is the home page.",
"globalDefaults": "<highlight>{globalString}</highlight>",
"rich": "This is a <important>rich</important> text.",
"rich": "This is a <b>rich</b> text.",
"title": "Home"
},
"JustIn": {
Expand Down
5 changes: 2 additions & 3 deletions examples/example-app-router-playground/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
},
"AsyncComponent": {
"basic": "AsyncComponent",
"markup": "Markup with <b>{globalString}</b>",
"markup": "Markup with <important>bold content</important>",
"rich": "This is a <important>rich</important> text."
},
"Client": {
Expand All @@ -21,8 +21,7 @@
},
"Index": {
"description": "Esta es la página de inicio.",
"globalDefaults": "<highlight>{globalString}</highlight>",
"rich": "Este es un texto <important>importante</important>.",
"rich": "Este es un texto <b>importante</b>.",
"title": "Inicio"
},
"JustIn": {
Expand Down
3 changes: 1 addition & 2 deletions examples/example-app-router-playground/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
},
"Index": {
"description": "This is the home page (ja).",
"globalDefaults": "<highlight>{globalString}</highlight> (ja)",
"rich": "This is a <important>rich</important> text (ja).",
"rich": "This is a <b>rich</b> text (ja).",
"title": "Home (ja)"
},
"JustIn": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import PageLayout from '../../components/PageLayout';
import MessagesAsPropsCounter from '../../components/client/01-MessagesAsPropsCounter';
import MessagesOnClientCounter from '../../components/client/02-MessagesOnClientCounter';
import DropdownMenu from '@/components/DropdownMenu';
import RichText from '@/components/RichText';
import {Link} from '@/i18n/routing';

type Props = {
Expand All @@ -27,14 +28,13 @@ export default function Index({searchParams}: Props) {
return (
<PageLayout title={t('title')}>
<p>{t('description')}</p>
<p data-testid="RichText">
{t.rich('rich', {important: (chunks) => <b>{chunks}</b>})}
</p>
<RichText data-testid="RichText">
{(tags) => t.rich('rich', tags)}
</RichText>
<p
dangerouslySetInnerHTML={{__html: t.raw('rich')}}
data-testid="RawText"
/>
<p data-testid="GlobalDefaults">{t.rich('globalDefaults')}</p>
{/* @ts-expect-error Purposefully trigger an error */}
<p data-testid="MissingMessage">{t('missing')}</p>
<p data-testid="CurrentTime">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ export default async function AsyncComponent() {
<div data-testid="AsyncComponent">
<p>{t('basic')}</p>
<p>{t.rich('rich', {important: (chunks) => <b>{chunks}</b>})}</p>
<p>{t.markup('markup', {b: (chunks) => `<b>${chunks}</b>`})}</p>
<p>
{t.markup('markup', {
important: (chunks) => `<b>${chunks}</b>`
})}
</p>
<p>{String(t.has('basic'))}</p>
</div>
);
Expand Down
18 changes: 18 additions & 0 deletions examples/example-app-router-playground/src/components/RichText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {ComponentProps, ReactNode} from 'react';

type Tag = 'b' | 'i';

type Props = {
children(tags: Record<Tag, (chunks: ReactNode) => ReactNode>): ReactNode;
} & Omit<ComponentProps<'p'>, 'children'>;

export default function RichText({children, ...rest}: Props) {
return (
<p {...rest}>
{children({
b: (chunks: ReactNode) => <b style={{fontWeight: 'bold'}}>{chunks}</b>,
i: (chunks: ReactNode) => <i style={{fontStyle: 'italic'}}>{chunks}</i>
})}
</p>
);
}
4 changes: 0 additions & 4 deletions examples/example-app-router-playground/src/i18n/request.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ export default getRequestConfig(async ({requestLocale}) => {
now: now ? new Date(now) : undefined,
timeZone,
messages,
defaultTranslationValues: {
globalString: 'Global string',
highlight: (chunks) => <strong>{chunks}</strong>
},
formats,
onError(error) {
if (
Expand Down
16 changes: 5 additions & 11 deletions examples/example-app-router-playground/tests/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,15 @@ it('can use next-intl on the client side', async ({page}) => {
it('can use rich text', async ({page}) => {
await page.goto('/en');
const element = page.getByTestId('RichText');
expect(await element.innerHTML()).toBe('This is a <b>rich</b> text.');
});

it('can use raw text', async ({page}) => {
await page.goto('/en');
const element = page.getByTestId('RawText');
expect(await element.innerHTML()).toBe(
'This is a <important>rich</important> text.'
'This is a <b style="font-weight:bold">rich</b> text.'
);
});

it('can use global defaults', async ({page}) => {
it('can use raw text', async ({page}) => {
await page.goto('/en');
const element = page.getByTestId('GlobalDefaults');
expect(await element.innerHTML()).toBe('<strong>Global string</strong>');
const element = page.getByTestId('RawText');
expect(await element.innerHTML()).toBe('This is a <b>rich</b> text.');
});

it('can use `getMessageFallback`', async ({page}) => {
Expand Down Expand Up @@ -642,7 +636,7 @@ it('can use async APIs in async components', async ({page}) => {
const element1 = page.getByTestId('AsyncComponent');
element1.getByText('AsyncComponent');
expect(await element1.innerHTML()).toContain('This is a <b>rich</b> text.');
element1.getByText('Markup with <b>Global string</b>');
element1.getByText('Markup with <b>bold content</b>');

page
.getByTestId('AsyncComponentWithoutNamespace')
Expand Down
5 changes: 4 additions & 1 deletion packages/use-intl/src/core/IntlConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ type IntlConfig<Messages = AbstractIntlMessages> = {
messages?: Messages;
/** Global default values for translation values and rich text elements.
* Can be used for consistent usage or styling of rich text elements.
* Defaults will be overidden by locally provided values. */
* Defaults will be overidden by locally provided values.
*
* @deprecated See https://next-intl-docs.vercel.app/docs/usage/messages#rich-text-reuse-tags
* */
defaultTranslationValues?: RichTranslationValues;
};

Expand Down
Loading