Skip to content

Commit e189a55

Browse files
committed
Allow using resource specific translations
1 parent 1a0078e commit e189a55

File tree

9 files changed

+265
-42
lines changed

9 files changed

+265
-42
lines changed

packages/ra-language-english/src/index.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,12 @@ const englishMessages: TranslationMessages = {
100100
bulk_delete_title:
101101
'Delete %{name} |||| Delete %{smart_count} %{name}',
102102
bulk_update_content:
103-
'Are you sure you want to update this %{name}? |||| Are you sure you want to update these %{smart_count} items?',
104-
bulk_update_content_record_representation:
105-
'Are you sure you want to update %{resource} %{name}? |||| Are you sure you want to update these %{smart_count} items?',
103+
'Are you sure you want to update %{name} %{recordRepresentation}? |||| Are you sure you want to update these %{smart_count} items?',
106104
bulk_update_title:
107-
'Update %{name} |||| Update %{smart_count} %{name}',
108-
bulk_update_title_record_representation:
109-
'Update %{resource} %{name} |||| Update %{smart_count} %{name}',
105+
'Update %{name} %{recordRepresentation} |||| Update %{smart_count} %{name}',
110106
clear_array_input: 'Are you sure you want to clear the whole list?',
111-
delete_content: 'Are you sure you want to delete this item?',
112-
delete_title: 'Delete %{name} #%{id}',
113-
delete_title_record_representation: 'Delete %{resource} %{name}',
107+
delete_content: 'Are you sure you want to delete this %{name}?',
108+
delete_title: 'Delete %{name} %{recordRepresentation}',
114109
details: 'Details',
115110
error: "A client error occurred and your request couldn't be completed.",
116111
invalid_form: 'The form is not valid. Please check for errors',

packages/ra-language-french/src/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,13 @@ const frenchMessages: TranslationMessages = {
102102
'Supprimer %{name} |||| Supprimer %{smart_count} %{name}',
103103
bulk_update_content:
104104
'Êtes-vous sûr(e) de vouloir modifier cet élément ? |||| Êtes-vous sûr(e) de vouloir modifier ces %{smart_count} éléments ?',
105-
bulk_update_content_record_representation:
106-
'Êtes-vous sûr(e) de vouloir modifier cet élément ? |||| Êtes-vous sûr(e) de vouloir modifier ces %{smart_count} éléments ?',
107105
bulk_update_title:
108106
'Modifier %{name} |||| Modifier %{smart_count} %{name}',
109107
clear_array_input:
110108
'Êtes-vous sûr(e) de vouloir supprimer tous les éléments de la liste ?',
111109
delete_content:
112110
'Êtes-vous sûr(e) de vouloir supprimer cet élément ?',
113-
delete_title: 'Supprimer %{name} #%{id}',
111+
delete_title: 'Supprimer %{name} %{recordRepresentation}',
114112
delete_title_record_representation: 'Supprimer %{name}',
115113
details: 'Détails',
116114
error: "En raison d'une erreur côté navigateur, votre requête n'a pas pu aboutir.",

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Notification } from '../layout';
2323
import {
2424
Basic,
2525
NoRecordRepresentation,
26+
WithDefaultTranslation,
2627
} from './DeleteWithConfirmButton.stories';
2728

2829
const theme = createTheme();
@@ -340,7 +341,7 @@ describe('<DeleteWithConfirmButton />', () => {
340341
});
341342
});
342343

343-
it('should use the record representation in the confirmation title', async () => {
344+
it('should use the record representation in the confirmation title and content with a resource specific translation', async () => {
344345
render(<Basic />);
345346
fireEvent.click(
346347
within(
@@ -349,10 +350,26 @@ describe('<DeleteWithConfirmButton />', () => {
349350
) as HTMLElement
350351
).getByText('Delete')
351352
);
353+
await screen.findByText('Delete the book "War and Peace"?');
354+
await screen.findByText(
355+
'Do you really want to delete the book "War and Peace"?'
356+
);
357+
});
358+
359+
it('should use the record representation in the confirmation title and content without a resource specific translation', async () => {
360+
render(<WithDefaultTranslation />);
361+
fireEvent.click(
362+
within(
363+
(await screen.findByText('War and Peace')).closest(
364+
'tr'
365+
) as HTMLElement
366+
).getByText('Delete')
367+
);
352368
await screen.findByText('Delete book War and Peace');
369+
await screen.findByText('Are you sure you want to delete this book?');
353370
});
354371

355-
it('should use the default translation in the confirmation title when no record representation is available', async () => {
372+
it('should use the default record representation in the confirmation title and title when no record representation is available', async () => {
356373
render(<NoRecordRepresentation />);
357374
fireEvent.click(
358375
within(
@@ -362,5 +379,6 @@ describe('<DeleteWithConfirmButton />', () => {
362379
).getByText('Delete')
363380
);
364381
await screen.findByText('Delete author #1');
382+
await screen.findByText('Are you sure you want to delete this author?');
365383
});
366384
});

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

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,50 @@ import { TextField } from '../field';
1515
export default { title: 'ra-ui-materialui/button/DeleteWithConfirmButton' };
1616

1717
const i18nProvider = polyglotI18nProvider(
18+
locale =>
19+
locale === 'fr'
20+
? {
21+
...frenchMessages,
22+
resources: {
23+
books: {
24+
name: 'Livre |||| Livres',
25+
fields: {
26+
id: 'Id',
27+
title: 'Titre',
28+
author: 'Auteur',
29+
year: 'Année',
30+
},
31+
message: {
32+
delete_title:
33+
'Supprimer le livre "%{recordRepresentation}" ?',
34+
delete_content:
35+
'Souhaitez-vous vraiment supprimer le livre "%{recordRepresentation}" ?',
36+
},
37+
},
38+
},
39+
}
40+
: {
41+
...englishMessages,
42+
resources: {
43+
books: {
44+
message: {
45+
delete_title:
46+
'Delete the book "%{recordRepresentation}"?',
47+
delete_content:
48+
'Do you really want to delete the book "%{recordRepresentation}"?',
49+
},
50+
},
51+
},
52+
},
53+
// Default locale
54+
'en',
55+
[
56+
{ locale: 'en', name: 'English' },
57+
{ locale: 'fr', name: 'Français' },
58+
]
59+
);
60+
61+
const i18nProviderDefault = polyglotI18nProvider(
1862
locale =>
1963
locale === 'fr'
2064
? {
@@ -32,7 +76,12 @@ const i18nProvider = polyglotI18nProvider(
3276
},
3377
}
3478
: englishMessages,
35-
'en' // Default locale
79+
// Default locale
80+
'en',
81+
[
82+
{ locale: 'en', name: 'English' },
83+
{ locale: 'fr', name: 'Français' },
84+
]
3685
);
3786

3887
const dataProvider = fakeRestDataProvider({
@@ -162,6 +211,26 @@ export const Basic = () => (
162211
</TestMemoryRouter>
163212
);
164213

214+
export const WithDefaultTranslation = () => (
215+
<TestMemoryRouter initialEntries={['/books']}>
216+
<AdminContext
217+
dataProvider={dataProvider}
218+
i18nProvider={i18nProviderDefault}
219+
>
220+
<AdminUI>
221+
<Resource
222+
name="books"
223+
list={
224+
<BookList>
225+
<DeleteWithConfirmButton />
226+
</BookList>
227+
}
228+
/>
229+
</AdminUI>
230+
</AdminContext>
231+
</TestMemoryRouter>
232+
);
233+
165234
export const NoRecordRepresentation = () => (
166235
<TestMemoryRouter initialEntries={['/authors']}>
167236
<AdminContext dataProvider={dataProvider} i18nProvider={i18nProvider}>

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

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,16 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
2525
const {
2626
className,
2727
confirmTitle: confirmTitleProp,
28-
confirmContent = 'ra.message.delete_content',
28+
confirmContent: confirmContentProp,
2929
confirmColor = 'primary',
3030
icon = defaultIcon,
3131
label = 'ra.action.delete',
3232
mutationMode = 'pessimistic',
3333
onClick,
3434
redirect = 'list',
3535
translateOptions = {},
36+
titleTranslateOptions = translateOptions,
37+
contentTranslateOptions = translateOptions,
3638
mutationOptions,
3739
color = 'error',
3840
successMessage,
@@ -58,9 +60,9 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
5860
successMessage,
5961
});
6062
const getRecordRepresentation = useGetRecordRepresentation(resource);
61-
const recordRepresentation = getRecordRepresentation(record);
62-
let confirmNameParam = recordRepresentation;
63-
let confirmTitle = 'ra.message.delete_title_record_representation';
63+
let recordRepresentation = getRecordRepresentation(record);
64+
let confirmTitle = `resources.${resource}.message.delete_title`;
65+
let confirmContent = `resources.${resource}.message.delete_content`;
6466
const resourceName = translate(`resources.${resource}.forcedCaseName`, {
6567
smart_count: 1,
6668
_: humanize(
@@ -71,10 +73,9 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
7173
true
7274
),
7375
});
74-
76+
// We don't support React elements for this
7577
if (isValidElement(recordRepresentation)) {
76-
confirmTitle = 'ra.message.delete_title';
77-
confirmNameParam = resourceName;
78+
recordRepresentation = `#${record?.id}`;
7879
}
7980

8081
return (
@@ -93,13 +94,29 @@ export const DeleteWithConfirmButton = <RecordType extends RaRecord = any>(
9394
isOpen={open}
9495
loading={isPending}
9596
title={confirmTitleProp ?? confirmTitle}
96-
content={confirmContent}
97+
content={confirmContentProp ?? confirmContent}
9798
confirmColor={confirmColor}
98-
translateOptions={{
99-
name: confirmNameParam,
100-
resource: resourceName,
99+
titleTranslateOptions={{
100+
recordRepresentation,
101+
name: resourceName,
102+
id: record?.id,
103+
_: translate('ra.message.delete_title', {
104+
recordRepresentation,
105+
name: resourceName,
106+
id: record?.id,
107+
}),
108+
...titleTranslateOptions,
109+
}}
110+
contentTranslateOptions={{
111+
recordRepresentation,
112+
name: resourceName,
101113
id: record?.id,
102-
...translateOptions,
114+
_: translate('ra.message.delete_content', {
115+
recordRepresentation,
116+
name: resourceName,
117+
id: record?.id,
118+
}),
119+
...contentTranslateOptions,
103120
}}
104121
onConfirm={handleDelete}
105122
onClose={handleDialogClose}
@@ -121,7 +138,12 @@ export interface DeleteWithConfirmButtonProps<
121138
mutationMode?: MutationMode;
122139
onClick?: ReactEventHandler<any>;
123140
// May be injected by Toolbar - sanitized in Button
141+
/**
142+
* @deprecated use `titleTranslateOptions` and `contentTranslateOptions` instead
143+
*/
124144
translateOptions?: object;
145+
titleTranslateOptions?: object;
146+
contentTranslateOptions?: object;
125147
mutationOptions?: UseMutationOptions<
126148
RecordType,
127149
MutationOptionsError,

packages/ra-ui-materialui/src/button/UpdateWithConfirmButton.spec.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { MutationOptions } from './UpdateButton.stories';
1919
import {
2020
Basic,
2121
NoRecordRepresentation,
22+
WithDefaultTranslation,
2223
} from './UpdateWithConfirmButton.stories';
2324

2425
const theme = createTheme();
@@ -279,7 +280,7 @@ describe('<UpdateWithConfirmButton />', () => {
279280
).toBeNull();
280281
});
281282

282-
it('should use the record representation in the confirmation title and content', async () => {
283+
it('should use the record representation in the confirmation title and content with a resource specific translation', async () => {
283284
render(<Basic />);
284285
fireEvent.click(
285286
within(
@@ -288,11 +289,39 @@ describe('<UpdateWithConfirmButton />', () => {
288289
) as HTMLElement
289290
).getByText('Update')
290291
);
292+
await screen.findByText('Update the book "War and Peace"?');
293+
await screen.findByText(
294+
'Do you really want to update the book "War and Peace"?'
295+
);
296+
});
297+
it('should use the record representation in the confirmation title and content without a resource specific translation', async () => {
298+
render(<WithDefaultTranslation />);
299+
fireEvent.click(
300+
within(
301+
(await screen.findByText('War and Peace')).closest(
302+
'tr'
303+
) as HTMLElement
304+
).getByText('Update')
305+
);
291306
await screen.findByText('Update book War and Peace');
292307
await screen.findByText(
293308
'Are you sure you want to update book War and Peace?'
294309
);
295310
});
311+
it('should use the record representation in the confirmation title and content', async () => {
312+
render(<Basic />);
313+
fireEvent.click(
314+
within(
315+
(await screen.findByText('War and Peace')).closest(
316+
'tr'
317+
) as HTMLElement
318+
).getByText('Update')
319+
);
320+
await screen.findByText('Update the book "War and Peace"?');
321+
await screen.findByText(
322+
'Do you really want to update the book "War and Peace"?'
323+
);
324+
});
296325

297326
it('should use the default translation in the confirmation title when no record representation is available', async () => {
298327
render(<NoRecordRepresentation />);
@@ -304,5 +333,6 @@ describe('<UpdateWithConfirmButton />', () => {
304333
).getByText('Update')
305334
);
306335
await screen.findByText('Update author #1');
336+
await screen.findByText('Are you sure you want to update author #1?');
307337
});
308338
});

0 commit comments

Comments
 (0)