Skip to content

Allow resource specific translations for pages and buttons #10686

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

Open
wants to merge 8 commits into
base: next
Choose a base branch
from
Open
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
160 changes: 154 additions & 6 deletions docs/Buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ const CommentList = () => (
| Prop | Required | Type | Default | Description |
| ------------- | -------- | --------------- | ------------------ | -------------------------------------------- |
| `resource` | Optional | `string` | - | Target resource, e.g. 'posts' |
| `label` | Optional | `string` | 'ra.action.create' | label or translation message to use |
| `label` | Optional | `string` | - | label or translation message to use |
| `icon` | Optional | `ReactElement` | - | iconElement, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |

Expand All @@ -704,6 +704,38 @@ It also supports [all the other `<Button>` props](#button).

**Tip:** To allow users to create a record without leaving the current view, use the [`<CreateInDialogButton>`](./CreateInDialogButton.md) component.

### `label`

By default, the label for the `<CreateButton>` is the translation key `ra.action.create` that translates to "Create".

You can customize this label by providing a resource specific translation with the key `resources.RESOURCE.action.create` (e.g. `resources.posts.action.create`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
action: {
create: 'New post'
}
},
},
...
};
```

You can also customize this label by specifying a custom `label` prop:

```jsx
export const PostCreateButton = () => (
<CreateButton label="New post" />
);
```

### `scrollToTop`

By default, `<CreateButton>` scrolls the page to the top after redirecting. You can disable it as follows:
Expand Down Expand Up @@ -766,7 +798,7 @@ You can also call it with a record and a resource:
| Prop | Required | Type | Default | Description |
|-------------------- |----------|--------------------------------- |-------------------|-------------------------------------------------------------------------|
| `className` | Optional | `string` | - | Class name to customize the look and feel of the button element itself |
| `label` | Optional | `string` | 'Delete' | label or translation message to use |
| `label` | Optional | `string` | - | label or translation message to use |
| `icon` | Optional | `ReactElement` | `<DeleteIcon>` | iconElement, e.g. `<CommentIcon />` |
| `mutationMode` | Optional | `string` | `'undoable'` | Mutation mode (`'undoable'`, `'pessimistic'` or `'optimistic'`) |
| `mutation Options` | Optional | | null | options for react-query `useMutation` hook |
Expand All @@ -780,7 +812,27 @@ You can also call it with a record and a resource:

By default, the label is `Delete` in English. In other languages, it's the translation of the `'ra.action.delete'` key.

To customize the `<DeleteButton>` label, you can either change the translation in your i18nProvider, or pass a `label` prop:
You can customize this label by providing a resource specific translation with the key `resources.RESOURCE.action.delete` (e.g. `resources.posts.action.delete`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
action: {
delete: 'Destroy %{recordRepresentation}'
}
},
},
...
};
```

You can also customize this label by specifying a custom `label` prop:

```jsx
<DeleteButton label="Delete this comment" />
Expand Down Expand Up @@ -975,7 +1027,7 @@ const CommentShow = () => (
| ------------- | -------- | --------------- | ---------------- | ------------------------------------------------ |
| `resource` | Optional | `string` | - | Resource to link to, e.g. 'posts' |
| `record` | Optional | `Object` | - | Record to link to, e.g. `{ id: 12, foo: 'bar' }` |
| `label` | Optional | `string` | 'ra.action.edit' | Label or translation message to use |
| `label` | Optional | `string` | - | Label or translation message to use |
| `icon` | Optional | `ReactElement` | - | Icon element, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |

Expand All @@ -987,6 +1039,39 @@ It also supports [all the other `<Button>` props](#button).

**Tip:** To allow users to edit a record without leaving the current view, use the [`<EditInDialogButton>`](./EditInDialogButton.md) component.

### `label`

By default, the label for the `<EditButton>` is the translation key `ra.action.edit` that translates to "Edit".

You can customize this label by providing a resource specific translation with the key `resources.RESOURCE.action.edit` (e.g. `resources.posts.action.edit`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
action: {
edit: 'Modify %{recordRepresentation}'
}
},
},
...
};
```

You can also customize this label by specifying a custom `label` prop:


```jsx
export const PostEditButton = () => (
<EditButton label="Modify" />
);
```

### `scrollToTop`

By default, `<EditButton>` scrolls the page to the top after redirecting. You can disable it as follows:
Expand Down Expand Up @@ -1152,12 +1237,42 @@ export const PostShow = () => (
| Prop | Required | Type | Default | Description |
| ------------- | -------- | --------------- | ---------------- | ---------------------------------------------- |
| `resource` | Optional | `string` | - | target resource, e.g. 'posts' |
| `label` | Optional | `string` | 'ra.action.list' | label or translation message to use |
| `label` | Optional | `string` | - | label or translation message to use |
| `icon` | Optional | `ReactElement` | - | iconElement, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |

It also supports [all the other `<Button>` props](#button).

### `label`

By default, the label is `List` in English. In other languages, it's the translation of the `'ra.action.list'` key.

You can customize this label by providing a resource specific translation with the key `resources.RESOURCE.action.list` (e.g. `resources.posts.action.list`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
action: {
list: 'See all posts'
}
},
},
...
};
```

You can also customize this label by specifying a custom `label` prop:

```jsx
<ListButton label="Delete this comment" />
```

### `scrollToTop`

By default, `<ListButton>` scrolls the page to the top after redirecting. You can disable it as follows:
Expand Down Expand Up @@ -1296,7 +1411,7 @@ const CommentEdit = () => (
| `resource` | Optional | `string` | - | The target resource, e.g. 'posts' |
| `record` | Optional | `Object` | - | Record to link to, e.g. `{ id: 12, foo: 'bar' }` |
| `component` | Optional | `ReactElement` | - | Base path to resource, e.g. '/posts' |
| `label` | Optional | `string` | 'ra.action.show' | Label or translation message to use |
| `label` | Optional | `string` | - | Label or translation message to use |
| `icon` | Optional | `ReactElement` | - | Icon element, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |

Expand All @@ -1306,6 +1421,39 @@ It also supports [all the other `<Button>` props](#button).

**Tip**: If you want to link to the Show view manually, use the `/{resource}/{record.id}/show` location.

### `label`

By default, the label for the `<ShowButton>` is the translation key `ra.action.show` that translates to "Show".

You can customize this label by providing a resource specific translation with the key `resources.RESOURCE.action.show` (e.g. `resources.posts.action.show`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
action: {
show: 'Display %{recordRepresentation}'
}
},
},
...
};
```

You can also customize this label by specifying a custom `label` prop:


```jsx
export const PostShowButton = () => (
<ShowButton label="Display" />
);
```

### `scrollToTop`

By default, `<ShowButton>` scrolls the page to the top after redirecting. You can disable it as follows:
Expand Down
24 changes: 22 additions & 2 deletions docs/Create.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,29 @@ To override the style of all instances of `<Create>` components using the [appli

## `title`

By default, the title for the `Create` view is "Create [resource_name]".
By default, the title for the `Create` view is the translation key `ra.page.create` that translates to "Create [resource_name]" as we also pass the translation of the [resource name](./TranslationTranslating.md#translating-resource-and-field-names) in its singular form.

You can customize this title by specifying a custom `title` prop:
You can customize this title by providing a resource specific translation with the key `resources.RESOURCE.page.create` (e.g. `resources.posts.page.create`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
page: {
create: 'New post'
}
},
},
...
};
```

You can also customize this title by specifying a custom `title` prop:

```jsx
export const PostCreate = () => (
Expand Down
24 changes: 22 additions & 2 deletions docs/Edit.md
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,29 @@ To override the style of all instances of `<Edit>` components using the [applica

## `title`

By default, the title for the Edit view is “Edit [resource_name] [record representation]”. Check the [`<Resource recordRepresentation>`](./Resource.md#recordrepresentation) prop for more details.
By default, the title for the Edit view is the translation key `ra.page.edit` that translates to “Edit [resource_name] [record representation]”. Check the [`<Resource recordRepresentation>`](./Resource.md#recordrepresentation) prop for more details.

You can customize this title by specifying a custom `title` string:
You can customize this title by providing a resource specific translation with the key `resources.RESOURCE.page.edit` (e.g. `resources.posts.page.edit`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
page: {
edit: 'Update post "%{recordRepresentation}"'
}
},
},
...
};
```

You can also customize this title by specifying a custom `title` string:

```jsx
export const PostEdit = () => (
Expand Down
24 changes: 22 additions & 2 deletions docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -976,11 +976,31 @@ const Admin = () => {

## `title`

The default title for a list view is the plural name of the resource (e.g. "Posts").
The default title for a list view is the translation key `ra.page.list` that translates to [the plural name of the resource](./TranslationTranslating.md#translating-resource-and-field-names) (e.g. "Posts").

![List title](./img/list-title.png)

Use the `title` prop to customize the List view title:
You can customize this title by providing a resource specific translation with the key `resources.RESOURCE.page.list` (e.g. `resources.posts.page.list`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
page: {
list: 'Post list'
}
},
},
...
};
```

You can also customize this title by specifying a custom `title` prop:

```jsx
export const PostList = () => (
Expand Down
24 changes: 22 additions & 2 deletions docs/Show.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,29 @@ To override the style of all instances of `<Show>` using the [application-wide s

## `title`

By default, the title for the Show view is "[resource_name] [record representation]". Check the [`<Resource recordRepresentation>`](./Resource.md#recordrepresentation) prop for more details.
By default, the title for the Show view is the translation key `ra.page.show` that translates to "[resource_name] [record representation]". Check the [`<Resource recordRepresentation>`](./Resource.md#recordrepresentation) prop for more details.

You can customize this title by providing a resource specific translation with the key `resources.RESOURCE.page.show` (e.g. `resources.posts.page.show`):

```js
// in src/i18n/en.js
import englishMessages from 'ra-language-english';

export const en = {
...englishMessages,
resources: {
posts: {
name: 'Post |||| Posts',
page: {
show: 'Details of post "%{recordRepresentation}"'
}
},
},
...
};
```

You can customize this title by specifying a custom `title` string:
You can also customize this title by specifying a custom `title` string:

```jsx
export const PostShow = () => (
Expand Down
15 changes: 15 additions & 0 deletions packages/ra-core/src/controller/create/CreateBase.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { screen, render, waitFor, fireEvent } from '@testing-library/react';
import { testDataProvider } from '../../dataProvider';
import {
AccessControl,
DefaultTitle,
NoAuthProvider,
WithAuthProviderNoAccessControl,
} from './CreateBase.stories';
Expand Down Expand Up @@ -268,4 +269,18 @@ describe('CreateBase', () => {
resolveCanAccess!(true);
await screen.findByText('save');
});

it('should provide a default title', async () => {
render(<DefaultTitle translations="default" />);
await screen.findByText('Create Post (en)');
fireEvent.click(screen.getByText('FR'));
await screen.findByText('Créer Article (fr)');
});

it('should allow resource specific default title', async () => {
render(<DefaultTitle translations="resource specific" />);
await screen.findByText('Create an article (en)');
fireEvent.click(screen.getByText('FR'));
await screen.findByText('Créer un article (fr)');
});
});
Loading
Loading