Skip to content

Commit dad7916

Browse files
committed
Introduce useResourceTranslation
1 parent 895d614 commit dad7916

File tree

9 files changed

+119
-87
lines changed

9 files changed

+119
-87
lines changed

packages/ra-core/src/i18n/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export * from './TranslationUtils';
1212
export * from './useLocaleState';
1313
export * from './useLocale';
1414
export * from './useLocales';
15+
export * from './useResourceTranslation';
1516
export * from './useSetLocale';
1617
export * from './useTranslatable';
1718
export * from './useTranslatableContext';
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type { ReactNode } from 'react';
2+
import { useTranslate } from './useTranslate';
3+
4+
export const useResourceTranslation = (
5+
params: UseResourceTranslationOptions
6+
) => {
7+
const { resourceI18nKey, baseI18nKey, userText, options } = params;
8+
const translate = useTranslate();
9+
10+
if (userText) {
11+
if (typeof userText !== 'string') {
12+
return userText;
13+
}
14+
return translate(userText, { _: userText, ...options });
15+
}
16+
17+
const translatedText = translate(resourceI18nKey, {
18+
...options,
19+
_: translate(baseI18nKey, options),
20+
});
21+
22+
return translatedText;
23+
};
24+
25+
export interface UseResourceTranslationOptions {
26+
resourceI18nKey: string;
27+
baseI18nKey: string;
28+
userText?: ReactNode;
29+
options?: Record<string, any>;
30+
}

packages/ra-ui-materialui/src/button/CreateButton.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import clsx from 'clsx';
1010
import isEqual from 'lodash/isEqual';
1111
import merge from 'lodash/merge';
1212
import {
13-
useTranslate,
14-
useResourceContext,
1513
useCreatePath,
1614
useCanAccess,
1715
useGetResourceLabel,
16+
useResourceContext,
17+
useResourceTranslation,
1818
} from 'ra-core';
1919
import { Link, type To } from 'react-router-dom';
2020

@@ -63,15 +63,15 @@ const CreateButton = (inProps: CreateButtonProps) => {
6363
resource,
6464
});
6565
const createPath = useCreatePath();
66-
const translate = useTranslate();
6766
const getResourceLabel = useGetResourceLabel();
68-
const label =
69-
labelProp ??
70-
translate(`resources.${resource}.action.create`, {
71-
_: translate(`ra.action.create`, {
72-
name: getResourceLabel(resource, 1),
73-
}),
74-
});
67+
const label = useResourceTranslation({
68+
resourceI18nKey: `resources.${resource}.action.create`,
69+
baseI18nKey: 'ra.action.create',
70+
options: {
71+
name: getResourceLabel(resource, 1),
72+
},
73+
userText: labelProp,
74+
});
7575
const isSmall = useMediaQuery((theme: Theme) =>
7676
theme.breakpoints.down('md')
7777
);

packages/ra-ui-materialui/src/button/DeleteWithConfirmButton.tsx

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
RedirectionSideEffect,
1515
useGetRecordRepresentation,
1616
useGetResourceLabel,
17+
useResourceTranslation,
1718
} from 'ra-core';
1819

1920
import { Confirm } from '../layout';
@@ -68,8 +69,6 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
6869
const getResourceLabel = useGetResourceLabel();
6970
const getRecordRepresentation = useGetRecordRepresentation(resource);
7071
let recordRepresentation = getRecordRepresentation(record);
71-
const confirmTitle = `resources.${resource}.message.delete_title`;
72-
const confirmContent = `resources.${resource}.message.delete_content`;
7372
const resourceName = translate(`resources.${resource}.forcedCaseName`, {
7473
smart_count: 1,
7574
_: humanize(
@@ -84,15 +83,37 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
8483
if (isValidElement(recordRepresentation)) {
8584
recordRepresentation = `#${record?.id}`;
8685
}
87-
const label =
88-
labelProp ??
89-
translate(`resources.${resource}.action.delete`, {
86+
const label = useResourceTranslation({
87+
resourceI18nKey: `resources.${resource}.action.delete`,
88+
baseI18nKey: 'ra.action.delete',
89+
options: {
90+
name: getResourceLabel(resource, 1),
9091
recordRepresentation,
91-
_: translate(`ra.action.delete`, {
92-
name: getResourceLabel(resource, 1),
93-
recordRepresentation,
94-
}),
95-
});
92+
},
93+
userText: labelProp,
94+
});
95+
const confirmTitle = useResourceTranslation({
96+
resourceI18nKey: `resources.${resource}.message.delete_title`,
97+
baseI18nKey: 'ra.message.delete_title',
98+
options: {
99+
recordRepresentation,
100+
name: resourceName,
101+
id: record?.id,
102+
...titleTranslateOptions,
103+
},
104+
userText: confirmTitleProp,
105+
});
106+
const confirmContent = useResourceTranslation({
107+
resourceI18nKey: `resources.${resource}.message.delete_content`,
108+
baseI18nKey: 'ra.message.delete_content',
109+
options: {
110+
recordRepresentation,
111+
name: resourceName,
112+
id: record?.id,
113+
...contentTranslateOptions,
114+
},
115+
userText: confirmContentProp,
116+
});
96117

97118
return (
98119
<Fragment>
@@ -112,35 +133,9 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
112133
<Confirm
113134
isOpen={open}
114135
loading={isPending}
115-
title={confirmTitleProp ?? confirmTitle}
116-
content={confirmContentProp ?? confirmContent}
136+
title={confirmTitle}
137+
content={confirmContent}
117138
confirmColor={confirmColor}
118-
titleTranslateOptions={{
119-
recordRepresentation,
120-
name: resourceName,
121-
id: record?.id,
122-
_:
123-
confirmTitleProp ??
124-
translate('ra.message.delete_title', {
125-
recordRepresentation,
126-
name: resourceName,
127-
id: record?.id,
128-
}),
129-
...titleTranslateOptions,
130-
}}
131-
contentTranslateOptions={{
132-
recordRepresentation,
133-
name: resourceName,
134-
id: record?.id,
135-
_:
136-
confirmContentProp ??
137-
translate('ra.message.delete_content', {
138-
recordRepresentation,
139-
name: resourceName,
140-
id: record?.id,
141-
}),
142-
...contentTranslateOptions,
143-
}}
144139
onConfirm={handleDelete}
145140
onClose={handleDialogClose}
146141
/>

packages/ra-ui-materialui/src/button/EditButton.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import {
1414
useRecordContext,
1515
useCreatePath,
1616
useCanAccess,
17-
useTranslate,
1817
useGetResourceLabel,
1918
useGetRecordRepresentation,
19+
useResourceTranslation,
2020
} from 'ra-core';
2121

2222
import { Button, ButtonProps } from './Button';
@@ -60,26 +60,25 @@ export const EditButton = <RecordType extends RaRecord = any>(
6060
resource,
6161
record,
6262
});
63-
const translate = useTranslate();
6463
const getResourceLabel = useGetResourceLabel();
6564
const getRecordRepresentation = useGetRecordRepresentation();
6665
const recordRepresentationValue = getRecordRepresentation(record);
6766

68-
if (!record || !canAccess || isPending) return null;
69-
7067
const recordRepresentation =
7168
typeof recordRepresentationValue === 'string'
7269
? recordRepresentationValue
7370
: recordRepresentationValue?.toString();
74-
const label =
75-
labelProp ??
76-
translate(`resources.${resource}.action.edit`, {
71+
const label = useResourceTranslation({
72+
resourceI18nKey: `resources.${resource}.action.edit`,
73+
baseI18nKey: 'ra.action.edit',
74+
options: {
75+
name: getResourceLabel(resource, 1),
7776
recordRepresentation,
78-
_: translate(`ra.action.edit`, {
79-
name: getResourceLabel(resource, 1),
80-
recordRepresentation,
81-
}),
82-
});
77+
},
78+
userText: labelProp,
79+
});
80+
81+
if (!record || !canAccess || isPending) return null;
8382

8483
return (
8584
<StyledButton

packages/ra-ui-materialui/src/button/IconButtonWithTooltip.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ export const IconButtonWithTooltip = ({
2323
setOpen(true);
2424
};
2525

26-
const translatedLabel = translate(label, { _: label });
26+
let translatedLabel = label;
27+
if (typeof label === 'string') {
28+
translatedLabel = translate(label, { _: label });
29+
}
2730

2831
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
2932
handleClose();
@@ -38,7 +41,11 @@ export const IconButtonWithTooltip = ({
3841
onClose={handleClose}
3942
>
4043
<IconButton
41-
aria-label={translatedLabel}
44+
aria-label={
45+
typeof translatedLabel === 'string'
46+
? translatedLabel
47+
: undefined
48+
}
4249
onClick={handleClick}
4350
{...props}
4451
/>
@@ -47,5 +54,5 @@ export const IconButtonWithTooltip = ({
4754
};
4855

4956
export interface IconButtonWithTooltipProps extends IconButtonProps {
50-
label: string;
57+
label: React.ReactNode;
5158
}

packages/ra-ui-materialui/src/button/ListButton.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import {
55
useResourceContext,
66
useCreatePath,
77
useCanAccess,
8-
useTranslate,
98
useGetResourceLabel,
9+
useResourceTranslation,
1010
} from 'ra-core';
1111

12-
import { Button, ButtonProps } from './Button';
12+
import { Button, type ButtonProps } from './Button';
1313

1414
/**
1515
* Opens the List view of a given resource
@@ -56,20 +56,20 @@ export const ListButton = (props: ListButtonProps) => {
5656
resource,
5757
});
5858
const createPath = useCreatePath();
59-
const translate = useTranslate();
6059
const getResourceLabel = useGetResourceLabel();
60+
const label = useResourceTranslation({
61+
resourceI18nKey: `resources.${resource}.action.list`,
62+
baseI18nKey: 'ra.action.list',
63+
options: {
64+
name: getResourceLabel(resource, 1),
65+
},
66+
userText: labelProp,
67+
});
68+
6169
if (!canAccess || isPending) {
6270
return null;
6371
}
6472

65-
const label =
66-
labelProp ??
67-
translate(`resources.${resource}.action.list`, {
68-
_: translate(`ra.action.list`, {
69-
name: getResourceLabel(resource, 1),
70-
}),
71-
});
72-
7373
return (
7474
<Button
7575
component={Link}

packages/ra-ui-materialui/src/button/ShowButton.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import { memo } from 'react';
33
import ImageEye from '@mui/icons-material/RemoveRedEye';
44
import { Link } from 'react-router-dom';
55
import {
6-
RaRecord,
6+
type RaRecord,
77
useResourceContext,
88
useRecordContext,
99
useCreatePath,
1010
useCanAccess,
11-
useTranslate,
1211
useGetResourceLabel,
1312
useGetRecordRepresentation,
13+
useResourceTranslation,
1414
} from 'ra-core';
1515

1616
import { Button, ButtonProps } from './Button';
@@ -52,26 +52,25 @@ const ShowButton = <RecordType extends RaRecord = any>(
5252
resource,
5353
record,
5454
});
55-
const translate = useTranslate();
5655
const getResourceLabel = useGetResourceLabel();
5756
const getRecordRepresentation = useGetRecordRepresentation();
5857
const recordRepresentationValue = getRecordRepresentation(record);
5958

60-
if (!record || !canAccess || isPending) return null;
61-
6259
const recordRepresentation =
6360
typeof recordRepresentationValue === 'string'
6461
? recordRepresentationValue
6562
: recordRepresentationValue?.toString();
66-
const label =
67-
labelProp ??
68-
translate(`resources.${resource}.action.show`, {
63+
const label = useResourceTranslation({
64+
resourceI18nKey: `resources.${resource}.action.show`,
65+
baseI18nKey: 'ra.action.show',
66+
options: {
67+
name: getResourceLabel(resource, 1),
6968
recordRepresentation,
70-
_: translate(`ra.action.show`, {
71-
name: getResourceLabel(resource, 1),
72-
recordRepresentation,
73-
}),
74-
});
69+
},
70+
userText: labelProp,
71+
});
72+
73+
if (!record || !canAccess || isPending) return null;
7574

7675
return (
7776
<Button

packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.spec.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ describe('InPlaceEditor', () => {
2424
await screen.findByText('Jane Doe');
2525
});
2626
it('should revert to the previous version on error', async () => {
27+
jest.spyOn(console, 'error').mockImplementation(() => {});
2728
render(<Basic delay={0} updateFails />);
2829
const value = await screen.findByText('John Doe');
2930
value.click();

0 commit comments

Comments
 (0)