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

[RFR] Add useTranslate hook #3188

Merged
merged 12 commits into from
May 6, 2019
36 changes: 29 additions & 7 deletions docs/Translation.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,23 +282,26 @@ const App = () => (

## Translating Your Own Components

React-admin package provides a `translate` Higher-Order Component, which simply passes the `translate` function as a prop to the wrapped component:
React-admin package provides a `useTranslate` hook, which simply returns the `translate` function:

```jsx
// in src/MyHelloButton.js
import React from 'react';
import { translate } from 'react-admin';
import { useTranslate } from 'react-admin';

const MyHelloButton = ({ translate }) => (
<button>{translate('myroot.hello.world')}</button>
);
const MyHelloButton = () => {
const translate = useTranslate();
return (
<button>{translate('myroot.hello.world')}</button>
);
}

export default translate(MyHelloButton);
export default MyHelloButton;
```

**Tip**: For your message identifiers, choose a different root name than `ra` and `resources`, which are reserved.

**Tip**: Don't use `translate` for Field and Input labels, or for page titles, as they are already translated:
**Tip**: Don't use `useTranslate` for Field and Input labels, or for page titles, as they are already translated:

```jsx
// don't do this
Expand All @@ -312,6 +315,25 @@ export default translate(MyHelloButton);
// and translate the `resources.customers.fields.first_name` key
```

If you're stuck with class components, react-admin also exports a `translate` higher-order component, which injects the `translate` function as prop.

```jsx
// in src/MyHelloButton.js
import React, { Component } from 'react';
import { translate as withTranslate } from 'react-admin';

class MyHelloButton extends Component {
render() {
const { translate } = this.props;
return (
<button>{translate('myroot.hello.world')}</button>
);
}
}

export default withTranslate(MyHelloButton);
```

## Using Specific Polyglot Features

Polyglot.js is a fantastic library: in addition to being small, fully maintained, and totally framework agnostic, it provides some nice features such as interpolation and pluralization, that you can use in react-admin.
Expand Down
17 changes: 10 additions & 7 deletions examples/demo/src/categories/CategoryEdit.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import React from 'react';
import {
translate,
Datagrid,
Edit,
EditButton,
NumberField,
ReferenceManyField,
SimpleForm,
TextInput,
useTranslate,
} from 'react-admin';

import ThumbnailField from '../products/ThumbnailField';
import ProductRefField from '../products/ProductRefField';

const CategoryTitle = translate(({ record, translate }) => (
<span>
{translate('resources.categories.name', { smart_count: 1 })} &quot;
{record.name}&quot;
</span>
));
const CategoryTitle = ({ record }) => {
const translate = useTranslate();
return (
<span>
{translate('resources.categories.name', { smart_count: 1 })} &quot;
{record.name}&quot;
</span>
);
};

const CategoryEdit = props => (
<Edit title={<CategoryTitle />} {...props}>
Expand Down
54 changes: 26 additions & 28 deletions examples/demo/src/categories/LinkToRelatedProducts.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from 'react';
import compose from 'recompose/compose';
import Button from '@material-ui/core/Button';
import { withStyles } from '@material-ui/core/styles';
import { Link } from 'react-router-dom';
import { translate } from 'react-admin';
import { useTranslate } from 'react-admin';
import { stringify } from 'query-string';

import products from '../products';
Expand All @@ -16,30 +15,29 @@ const styles = {
},
};

const LinkToRelatedProducts = ({ classes, record, translate }) => (
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff looks much better with 'hide whitespace changes' turned on.

<Button
size="small"
color="primary"
component={Link}
to={{
pathname: '/products',
search: stringify({
page: 1,
perPage: 25,
sort: 'id',
order: 'DESC',
filter: JSON.stringify({ category_id: record.id }),
}),
}}
className={classes.link}
>
<products.icon className={classes.icon} />
{translate('resources.categories.fields.products')}
</Button>
);
const LinkToRelatedProducts = ({ classes, record }) => {
const translate = useTranslate();
return (
<Button
size="small"
color="primary"
component={Link}
to={{
pathname: '/products',
search: stringify({
page: 1,
perPage: 25,
sort: 'id',
order: 'DESC',
filter: JSON.stringify({ category_id: record.id }),
}),
}}
className={classes.link}
>
<products.icon className={classes.icon} />
{translate('resources.categories.fields.products')}
</Button>
);
};

const enhance = compose(
withStyles(styles),
translate
);
export default enhance(LinkToRelatedProducts);
export default withStyles(styles)(LinkToRelatedProducts);
95 changes: 49 additions & 46 deletions examples/demo/src/configuration/Configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import Button from '@material-ui/core/Button';
import { translate, changeLocale, Title } from 'react-admin';
import { useTranslate, changeLocale, Title } from 'react-admin';
import withStyles from '@material-ui/core/styles/withStyles';
import compose from 'recompose/compose';
import { changeTheme } from './actions';
Expand All @@ -19,50 +19,54 @@ const Configuration = ({
locale,
changeTheme,
changeLocale,
translate,
}) => (
<Card>
<Title title={translate('pos.configuration')} />
<CardContent>
<div className={classes.label}>{translate('pos.theme.name')}</div>
<Button
variant="raised"
className={classes.button}
color={theme === 'light' ? 'primary' : 'default'}
onClick={() => changeTheme('light')}
>
{translate('pos.theme.light')}
</Button>
<Button
variant="raised"
className={classes.button}
color={theme === 'dark' ? 'primary' : 'default'}
onClick={() => changeTheme('dark')}
>
{translate('pos.theme.dark')}
</Button>
</CardContent>
<CardContent>
<div className={classes.label}>{translate('pos.language')}</div>
<Button
variant="raised"
className={classes.button}
color={locale === 'en' ? 'primary' : 'default'}
onClick={() => changeLocale('en')}
>
en
</Button>
<Button
variant="raised"
className={classes.button}
color={locale === 'fr' ? 'primary' : 'default'}
onClick={() => changeLocale('fr')}
>
fr
</Button>
</CardContent>
</Card>
);
}) => {
const translate = useTranslate();
return (
<Card>
<Title title={translate('pos.configuration')} />
<CardContent>
<div className={classes.label}>
{translate('pos.theme.name')}
</div>
<Button
variant="raised"
className={classes.button}
color={theme === 'light' ? 'primary' : 'default'}
onClick={() => changeTheme('light')}
>
{translate('pos.theme.light')}
</Button>
<Button
variant="raised"
className={classes.button}
color={theme === 'dark' ? 'primary' : 'default'}
onClick={() => changeTheme('dark')}
>
{translate('pos.theme.dark')}
</Button>
</CardContent>
<CardContent>
<div className={classes.label}>{translate('pos.language')}</div>
<Button
variant="raised"
className={classes.button}
color={locale === 'en' ? 'primary' : 'default'}
onClick={() => changeLocale('en')}
>
en
</Button>
<Button
variant="raised"
className={classes.button}
color={locale === 'fr' ? 'primary' : 'default'}
onClick={() => changeLocale('fr')}
>
fr
</Button>
</CardContent>
</Card>
);
};

const mapStateToProps = state => ({
theme: state.theme,
Expand All @@ -77,7 +81,6 @@ const enhance = compose(
changeTheme,
}
),
translate,
withStyles(styles)
);

Expand Down
39 changes: 18 additions & 21 deletions examples/demo/src/dashboard/MonthlyRevenue.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import compose from 'recompose/compose';
import Card from '@material-ui/core/Card';
import DollarIcon from '@material-ui/icons/AttachMoney';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import { translate } from 'react-admin';
import { useTranslate } from 'react-admin';

import CardIcon from './CardIcon';

Expand All @@ -22,23 +21,21 @@ const styles = {
},
};

const MonthlyRevenue = ({ value, translate, classes }) => (
<div className={classes.main}>
<CardIcon Icon={DollarIcon} bgColor="#31708f" />
<Card className={classes.card}>
<Typography className={classes.title} color="textSecondary">
{translate('pos.dashboard.monthly_revenue')}
</Typography>
<Typography variant="headline" component="h2">
{value}
</Typography>
</Card>
</div>
);

const enhance = compose(
withStyles(styles),
translate
);
const MonthlyRevenue = ({ value, classes }) => {
const translate = useTranslate();
return (
<div className={classes.main}>
<CardIcon Icon={DollarIcon} bgColor="#31708f" />
<Card className={classes.card}>
<Typography className={classes.title} color="textSecondary">
{translate('pos.dashboard.monthly_revenue')}
</Typography>
<Typography variant="headline" component="h2">
{value}
</Typography>
</Card>
</div>
);
};

export default enhance(MonthlyRevenue);
export default withStyles(styles)(MonthlyRevenue);
39 changes: 18 additions & 21 deletions examples/demo/src/dashboard/NbNewOrders.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import compose from 'recompose/compose';
import Card from '@material-ui/core/Card';
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import { translate } from 'react-admin';
import { useTranslate } from 'react-admin';

import CardIcon from './CardIcon';

Expand All @@ -22,23 +21,21 @@ const styles = {
},
};

const NbNewOrders = ({ value, translate, classes }) => (
<div className={classes.main}>
<CardIcon Icon={ShoppingCartIcon} bgColor="#ff9800" />
<Card className={classes.card}>
<Typography className={classes.title} color="textSecondary">
{translate('pos.dashboard.new_orders')}
</Typography>
<Typography variant="headline" component="h2">
{value}
</Typography>
</Card>
</div>
);

const enhance = compose(
withStyles(styles),
translate
);
const NbNewOrders = ({ value, classes }) => {
const translate = useTranslate();
return (
<div className={classes.main}>
<CardIcon Icon={ShoppingCartIcon} bgColor="#ff9800" />
<Card className={classes.card}>
<Typography className={classes.title} color="textSecondary">
{translate('pos.dashboard.new_orders')}
</Typography>
<Typography variant="headline" component="h2">
{value}
</Typography>
</Card>
</div>
);
};

export default enhance(NbNewOrders);
export default withStyles(styles)(NbNewOrders);
Loading