Clean any trace of i18next

This commit is contained in:
dominik-zeglen 2019-08-29 12:55:56 +02:00
parent e2e75dcc49
commit faaaea773a
34 changed files with 623 additions and 321 deletions

21
package-lock.json generated
View file

@ -2862,12 +2862,6 @@
"hoist-non-react-statics": "^3.3.0" "hoist-non-react-statics": "^3.3.0"
} }
}, },
"@types/i18next": {
"version": "8.4.6",
"resolved": "https://registry.npmjs.org/@types/i18next/-/i18next-8.4.6.tgz",
"integrity": "sha512-ZiSCqW8j9/gQCYixz1nMhyCprSGh3rwdyX+FHAzEN+bMCmc7yCYjNutl6jvMYSxSIGeL0CLEXPM8Nlk2lE0t5w==",
"dev": true
},
"@types/invariant": { "@types/invariant": {
"version": "2.2.30", "version": "2.2.30",
"resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.30.tgz", "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.30.tgz",
@ -10921,21 +10915,6 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz",
"integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==" "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ=="
}, },
"i18next": {
"version": "11.10.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-11.10.2.tgz",
"integrity": "sha512-1rowdX8PqrvsdFhYb3v0A/LlIHLQL1HTa4ia29IzhvNAg2fesNV7R1jXibWLmLQdz3FfTB8RuqSqDEjIawXruA=="
},
"i18next-browser-languagedetector": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.2.4.tgz",
"integrity": "sha512-wPbtH18FdOuB245I8Bhma5/XSDdN/HpYlX+wga1eMy+slhaFQSnrWX6fp+aYSL2eEuj0RlfHeEVz6Fo/lxAj6A=="
},
"i18next-xhr-backend": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-1.5.1.tgz",
"integrity": "sha512-9OLdC/9YxDvTFcgsH5t2BHCODHEotHCa6h7Ly0EUlUC7Y2GS09UeoHOGj3gWKQ3HCqXz8NlH4gOrK3NNc9vPuw=="
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",

View file

@ -39,9 +39,6 @@
"fuzzaldrin": "^2.1.0", "fuzzaldrin": "^2.1.0",
"graphql": "^14.4.2", "graphql": "^14.4.2",
"graphql-tag": "^2.10.1", "graphql-tag": "^2.10.1",
"i18next": "^11.10.2",
"i18next-browser-languagedetector": "^2.2.4",
"i18next-xhr-backend": "^1.5.1",
"is-url": "^1.2.4", "is-url": "^1.2.4",
"jss": "^9.8.7", "jss": "^9.8.7",
"keycode": "^2.2.0", "keycode": "^2.2.0",
@ -88,7 +85,6 @@
"@types/draft-js": "^0.10.34", "@types/draft-js": "^0.10.34",
"@types/enzyme": "^3.10.2", "@types/enzyme": "^3.10.2",
"@types/fuzzaldrin": "^2.1.2", "@types/fuzzaldrin": "^2.1.2",
"@types/i18next": "^8.4.6",
"@types/jest": "^23.3.14", "@types/jest": "^23.3.14",
"@types/lodash-es": "^4.17.3", "@types/lodash-es": "^4.17.3",
"@types/moment-timezone": "^0.5.12", "@types/moment-timezone": "^0.5.12",

View file

@ -6,15 +6,15 @@ import TableFooter from "@material-ui/core/TableFooter";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import makeStyles from "@material-ui/styles/makeStyles"; import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import Checkbox from "@saleor/components/Checkbox"; import Checkbox from "@saleor/components/Checkbox";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import { translateBoolean } from "@saleor/intl";
import { renderCollection } from "@saleor/misc"; import { renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types"; import { ListActions, ListProps } from "@saleor/types";
import { translateBoolean } from "@saleor/utils/i18n";
import { AttributeList_attributes_edges_node } from "../../types/AttributeList"; import { AttributeList_attributes_edges_node } from "../../types/AttributeList";
export interface AttributeListProps extends ListProps, ListActions { export interface AttributeListProps extends ListProps, ListActions {
@ -71,6 +71,7 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
toolbar toolbar
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl();
return ( return (
<Table> <Table>
@ -153,21 +154,21 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
</TableCell> </TableCell>
<TableCell className={classes.colVisible}> <TableCell className={classes.colVisible}>
{attribute ? ( {attribute ? (
translateBoolean(attribute.visibleInStorefront) translateBoolean(attribute.visibleInStorefront, intl)
) : ( ) : (
<Skeleton /> <Skeleton />
)} )}
</TableCell> </TableCell>
<TableCell className={classes.colSearchable}> <TableCell className={classes.colSearchable}>
{attribute ? ( {attribute ? (
translateBoolean(attribute.filterableInDashboard) translateBoolean(attribute.filterableInDashboard, intl)
) : ( ) : (
<Skeleton /> <Skeleton />
)} )}
</TableCell> </TableCell>
<TableCell className={classes.colFaceted}> <TableCell className={classes.colFaceted}>
{attribute ? ( {attribute ? (
translateBoolean(attribute.filterableInStorefront) translateBoolean(attribute.filterableInStorefront, intl)
) : ( ) : (
<Skeleton /> <Skeleton />
)} )}

View file

@ -9,6 +9,7 @@ import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
import SVG from "react-inlinesvg"; import SVG from "react-inlinesvg";
import { FormattedMessage, useIntl } from "react-intl";
import backgroundArt from "@assets/images/login-background.svg"; import backgroundArt from "@assets/images/login-background.svg";
import saleorDarkLogo from "@assets/images/logo-dark.svg"; import saleorDarkLogo from "@assets/images/logo-dark.svg";
@ -17,7 +18,7 @@ import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import { FormSpacer } from "@saleor/components/FormSpacer"; import { FormSpacer } from "@saleor/components/FormSpacer";
import useTheme from "@saleor/hooks/useTheme"; import useTheme from "@saleor/hooks/useTheme";
import i18n from "@saleor/i18n"; import { commonMessages } from "@saleor/intl";
export interface FormData { export interface FormData {
email: string; email: string;
@ -117,6 +118,7 @@ export interface LoginCardProps extends WithStyles<typeof styles> {
const LoginCard = withStyles(styles, { name: "LoginCard" })( const LoginCard = withStyles(styles, { name: "LoginCard" })(
({ classes, error, disableLoginButton, onSubmit }: LoginCardProps) => { ({ classes, error, disableLoginButton, onSubmit }: LoginCardProps) => {
const { isDark } = useTheme(); const { isDark } = useTheme();
const intl = useIntl();
return ( return (
<Form <Form
@ -136,21 +138,16 @@ const LoginCard = withStyles(styles, { name: "LoginCard" })(
/> />
{error && ( {error && (
<div className={classes.panel}> <div className={classes.panel}>
<Typography <Typography variant="caption">
variant="caption" <FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." />
dangerouslySetInnerHTML={{ </Typography>
__html: i18n.t(
"Sorry, your username and/or password are incorrect. <br />Please try again."
)
}}
/>
</div> </div>
)} )}
<TextField <TextField
autoFocus autoFocus
fullWidth fullWidth
autoComplete="username" autoComplete="username"
label={i18n.t("Email", { context: "form" })} label={intl.formatMessage(commonMessages.email)}
name="email" name="email"
onChange={handleChange} onChange={handleChange}
value={data.email} value={data.email}
@ -162,7 +159,9 @@ const LoginCard = withStyles(styles, { name: "LoginCard" })(
<TextField <TextField
fullWidth fullWidth
autoComplete="current-password" autoComplete="current-password"
label={i18n.t("Password")} label={intl.formatMessage({
defaultMessage: "Password"
})}
name="password" name="password"
onChange={handleChange} onChange={handleChange}
type="password" type="password"
@ -173,7 +172,10 @@ const LoginCard = withStyles(styles, { name: "LoginCard" })(
<div className={classes.buttonContainer}> <div className={classes.buttonContainer}>
<ControlledCheckbox <ControlledCheckbox
checked={data.rememberMe} checked={data.rememberMe}
label={i18n.t("Remember me")} label={intl.formatMessage({
defaultMessage: "Remember me",
description: "login"
})}
name="rememberMe" name="rememberMe"
onChange={handleChange} onChange={handleChange}
/> />
@ -187,7 +189,10 @@ const LoginCard = withStyles(styles, { name: "LoginCard" })(
type="submit" type="submit"
data-tc="submit" data-tc="submit"
> >
{i18n.t("Login")} <FormattedMessage
defaultMessage="Login"
description="button"
/>
</Button> </Button>
</div> </div>
{/* <FormSpacer /> {/* <FormSpacer />

View file

@ -1,8 +1,10 @@
import { parse as parseQs } from "qs"; import { parse as parseQs } from "qs";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import { Route, RouteComponentProps, Switch } from "react-router-dom"; import { Route, RouteComponentProps, Switch } from "react-router-dom";
import { sectionNames } from "@saleor/intl";
import { WindowTitle } from "../components/WindowTitle"; import { WindowTitle } from "../components/WindowTitle";
import i18n from "../i18n";
import { import {
categoryAddPath, categoryAddPath,
categoryListPath, categoryListPath,
@ -56,16 +58,20 @@ const CategoryList: React.StatelessComponent<RouteComponentProps<{}>> = ({
return <CategoryListComponent params={params} />; return <CategoryListComponent params={params} />;
}; };
const Component = () => ( const Component = () => {
<> const intl = useIntl();
<WindowTitle title={i18n.t("Categories")} />
<Switch> return (
<Route exact path={categoryListPath} component={CategoryList} /> <>
<Route exact path={categoryAddPath()} component={CategoryCreate} /> <WindowTitle title={intl.formatMessage(sectionNames.categories)} />
<Route exact path={categoryAddPath(":id")} component={CategoryCreate} /> <Switch>
<Route path={categoryPath(":id")} component={CategoryDetails} /> <Route exact path={categoryListPath} component={CategoryList} />
</Switch> <Route exact path={categoryAddPath()} component={CategoryCreate} />
</> <Route exact path={categoryAddPath(":id")} component={CategoryCreate} />
); <Route path={categoryPath(":id")} component={CategoryDetails} />
</Switch>
</>
);
};
export default Component; export default Component;

View file

@ -17,7 +17,7 @@ import {
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import SVG from "react-inlinesvg"; import SVG from "react-inlinesvg";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { RouteComponentProps, withRouter } from "react-router"; import { RouteComponentProps, withRouter } from "react-router";
import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg"; import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg";
@ -34,7 +34,7 @@ import AppActionContext from "./AppActionContext";
import AppHeaderContext from "./AppHeaderContext"; import AppHeaderContext from "./AppHeaderContext";
import { appLoaderHeight, drawerWidth, drawerWidthExpanded } from "./consts"; import { appLoaderHeight, drawerWidth, drawerWidthExpanded } from "./consts";
import MenuList from "./MenuList"; import MenuList from "./MenuList";
import menuStructure from "./menuStructure"; import createMenuStructure from "./menuStructure";
import ResponsiveDrawer from "./ResponsiveDrawer"; import ResponsiveDrawer from "./ResponsiveDrawer";
import ThemeSwitch from "./ThemeSwitch"; import ThemeSwitch from "./ThemeSwitch";
@ -108,9 +108,7 @@ const styles = (theme: Theme) =>
}, },
isMenuSmallDark: { isMenuSmallDark: {
"&:hover": { "&:hover": {
background: `linear-gradient(0deg, rgba(25, 195, 190, 0.1), rgba(25, 195, 190, 0.1)), ${ background: `linear-gradient(0deg, rgba(25, 195, 190, 0.1), rgba(25, 195, 190, 0.1)), ${theme.palette.background.paper}`
theme.palette.background.paper
}`
}, },
border: `solid 1px #252728`, border: `solid 1px #252728`,
transition: `background ${theme.transitions.duration.shorter}ms` transition: `background ${theme.transitions.duration.shorter}ms`
@ -277,6 +275,9 @@ const AppLayout = withStyles(styles, {
const anchor = React.useRef<HTMLDivElement>(); const anchor = React.useRef<HTMLDivElement>();
const { logout, user } = useUser(); const { logout, user } = useUser();
const navigate = useNavigator(); const navigate = useNavigator();
const intl = useIntl();
const menuStructure = createMenuStructure(intl);
const handleLogout = () => { const handleLogout = () => {
close(); close();

View file

@ -2,7 +2,6 @@ import { categoryListUrl } from "../../categories/urls";
import { collectionListUrl } from "../../collections/urls"; import { collectionListUrl } from "../../collections/urls";
import { customerListUrl } from "../../customers/urls"; import { customerListUrl } from "../../customers/urls";
import { saleListUrl, voucherListUrl } from "../../discounts/urls"; import { saleListUrl, voucherListUrl } from "../../discounts/urls";
import i18n from "../../i18n";
import { orderDraftListUrl, orderListUrl } from "../../orders/urls"; import { orderDraftListUrl, orderListUrl } from "../../orders/urls";
import { productListUrl } from "../../products/urls"; import { productListUrl } from "../../products/urls";
import { languageListUrl } from "../../translations/urls"; import { languageListUrl } from "../../translations/urls";
@ -14,6 +13,8 @@ import discountsIcon from "@assets/images/menu-discounts-icon.svg";
import homeIcon from "@assets/images/menu-home-icon.svg"; import homeIcon from "@assets/images/menu-home-icon.svg";
import ordersIcon from "@assets/images/menu-orders-icon.svg"; import ordersIcon from "@assets/images/menu-orders-icon.svg";
import translationIcon from "@assets/images/menu-translation-icon.svg"; import translationIcon from "@assets/images/menu-translation-icon.svg";
import { commonMessages, sectionNames } from "@saleor/intl";
import { IntlShape } from "react-intl";
export interface IMenuItem { export interface IMenuItem {
ariaLabel: string; ariaLabel: string;
@ -24,88 +25,91 @@ export interface IMenuItem {
url?: string; url?: string;
} }
const menuStructure: IMenuItem[] = [ function createMenuStructure(intl: IntlShape): IMenuItem[] {
{ return [
ariaLabel: "home", {
icon: homeIcon, ariaLabel: "home",
label: i18n.t("Home", { context: "Menu label" }), icon: homeIcon,
url: "/" label: intl.formatMessage(sectionNames.home),
}, url: "/"
{ },
ariaLabel: "catalogue", {
children: [ ariaLabel: "catalogue",
{ children: [
ariaLabel: "products", {
label: i18n.t("Products", { context: "Menu label" }), ariaLabel: "products",
url: productListUrl() label: intl.formatMessage(sectionNames.products),
}, url: productListUrl()
{ },
ariaLabel: "categories", {
label: i18n.t("Categories", { context: "Menu label" }), ariaLabel: "categories",
url: categoryListUrl() label: intl.formatMessage(sectionNames.categories),
}, url: categoryListUrl()
{ },
ariaLabel: "collections", {
label: i18n.t("Collections", { context: "Menu label" }), ariaLabel: "collections",
url: collectionListUrl() label: intl.formatMessage(sectionNames.collections),
} url: collectionListUrl()
], }
icon: catalogIcon, ],
label: i18n.t("Catalog", { context: "Menu label" }), icon: catalogIcon,
permission: PermissionEnum.MANAGE_PRODUCTS label: intl.formatMessage(commonMessages.catalog),
}, permission: PermissionEnum.MANAGE_PRODUCTS
{ },
ariaLabel: "orders", {
children: [ ariaLabel: "orders",
{ children: [
ariaLabel: "orders", {
label: i18n.t("Orders", { context: "Menu label" }), ariaLabel: "orders",
permission: PermissionEnum.MANAGE_ORDERS, label: intl.formatMessage(sectionNames.orders),
url: orderListUrl() permission: PermissionEnum.MANAGE_ORDERS,
}, url: orderListUrl()
{ },
ariaLabel: "order drafts", {
label: i18n.t("Drafts", { context: "Menu label" }), ariaLabel: "order drafts",
permission: PermissionEnum.MANAGE_ORDERS, label: intl.formatMessage(commonMessages.drafts),
url: orderDraftListUrl() permission: PermissionEnum.MANAGE_ORDERS,
} url: orderDraftListUrl()
], }
icon: ordersIcon, ],
label: i18n.t("Orders", { context: "Menu label" }), icon: ordersIcon,
permission: PermissionEnum.MANAGE_ORDERS label: intl.formatMessage(sectionNames.orders),
}, permission: PermissionEnum.MANAGE_ORDERS
{ },
ariaLabel: "customers", {
icon: customerIcon, ariaLabel: "customers",
label: i18n.t("Customers", { context: "Menu label" }), icon: customerIcon,
permission: PermissionEnum.MANAGE_USERS, label: intl.formatMessage(sectionNames.customers),
url: customerListUrl() permission: PermissionEnum.MANAGE_USERS,
}, url: customerListUrl()
},
{ {
ariaLabel: "discounts", ariaLabel: "discounts",
children: [ children: [
{ {
ariaLabel: "sales", ariaLabel: "sales",
label: i18n.t("Sales", { context: "Menu label" }), label: intl.formatMessage(sectionNames.sales),
url: saleListUrl() url: saleListUrl()
}, },
{ {
ariaLabel: "vouchers", ariaLabel: "vouchers",
label: i18n.t("Vouchers", { context: "Menu label" }), label: intl.formatMessage(sectionNames.vouchers),
url: voucherListUrl() url: voucherListUrl()
} }
], ],
icon: discountsIcon, icon: discountsIcon,
label: i18n.t("Discounts", { context: "Menu label" }), label: intl.formatMessage(commonMessages.discounts),
permission: PermissionEnum.MANAGE_DISCOUNTS permission: PermissionEnum.MANAGE_DISCOUNTS
}, },
{ {
ariaLabel: "translations", ariaLabel: "translations",
icon: translationIcon, icon: translationIcon,
label: i18n.t("Translations", { context: "Menu label" }), label: intl.formatMessage(sectionNames.translations),
permission: PermissionEnum.MANAGE_TRANSLATIONS, permission: PermissionEnum.MANAGE_TRANSLATIONS,
url: languageListUrl url: languageListUrl
} }
]; ];
export default menuStructure; }
export default createMenuStructure;

View file

@ -1,5 +1,4 @@
export { default } from "./FilterTabs"; export { default } from "./FilterTabs";
export { Filter } from "./FilterChips";
export * from "./FilterTabs"; export * from "./FilterTabs";
export * from "./FilterTab"; export * from "./FilterTab";
export * from "./FilterChips"; export * from "./FilterChips";

View file

@ -44,7 +44,7 @@ const CustomerOrders = withStyles(styles, { name: "CustomerOrders" })(
const orderList = orders const orderList = orders
? orders.map(order => ({ ? orders.map(order => ({
...order, ...order,
paymentStatus: transformPaymentStatus(order.paymentStatus) paymentStatus: transformPaymentStatus(order.paymentStatus, intl)
})) }))
: undefined; : undefined;
return ( return (

View file

@ -29,7 +29,7 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const translatedVoucherTypes = translateVoucherTypes(); const translatedVoucherTypes = translateVoucherTypes(intl);
return ( return (
<Card> <Card>

View file

@ -39,7 +39,7 @@ const VoucherValue = ({
}: VoucherValueProps) => { }: VoucherValueProps) => {
const intl = useIntl(); const intl = useIntl();
const translatedVoucherTypes = translateVoucherTypes(); const translatedVoucherTypes = translateVoucherTypes(intl);
const voucherTypeChoices = Object.values(VoucherType).map(type => ({ const voucherTypeChoices = Object.values(VoucherType).map(type => ({
label: translatedVoucherTypes[type], label: translatedVoucherTypes[type],
value: type value: type

View file

@ -1,8 +1,24 @@
import i18n from "../i18n"; import { defineMessages, IntlShape } from "react-intl";
import { VoucherTypeEnum } from "../types/globalTypes"; import { VoucherTypeEnum } from "../types/globalTypes";
export const translateVoucherTypes = () => ({ const messages = defineMessages({
[VoucherTypeEnum.SHIPPING]: i18n.t("Shipment"), order: {
[VoucherTypeEnum.ENTIRE_ORDER]: i18n.t("Entire order"), defaultMessage: "Entire order",
[VoucherTypeEnum.SPECIFIC_PRODUCT]: i18n.t("Specific Products") description: "voucher discount"
},
products: {
defaultMessage: "Specific products",
description: "voucher discount"
},
shipment: {
defaultMessage: "Shipment",
description: "voucher discount"
}
});
export const translateVoucherTypes = (intl: IntlShape) => ({
[VoucherTypeEnum.SHIPPING]: intl.formatMessage(messages.shipment),
[VoucherTypeEnum.ENTIRE_ORDER]: intl.formatMessage(messages.order),
[VoucherTypeEnum.SPECIFIC_PRODUCT]: intl.formatMessage(messages.products)
}); });

View file

@ -50,7 +50,9 @@ const HomeActivityCard = withStyles(styles, { name: "HomeActivityCard" })(
{activity ? ( {activity ? (
<ListItemText <ListItemText
primary={ primary={
<Typography>{getActivityMessage(activity)}</Typography> <Typography>
{getActivityMessage(activity, intl)}
</Typography>
} }
secondary={<DateTime date={activity.date} />} secondary={<DateTime date={activity.date} />}
/> />

View file

@ -1,25 +1,38 @@
import i18n from "../../../i18n"; import { defineMessages, IntlShape } from "react-intl";
import { OrderEventsEnum } from "../../../types/globalTypes"; import { OrderEventsEnum } from "../../../types/globalTypes";
import { Home_activities_edges_node } from "../../types/Home"; import { Home_activities_edges_node } from "../../types/Home";
export const getActivityMessage = (activity: Home_activities_edges_node) => { const messages = defineMessages({
draft: {
defaultMessage: "Order #{orderId} was placed from draft by {userEmail}"
},
paid: {
defaultMessage: "Order #{orderId} was fully paid"
},
placed: {
defaultMessage: "Order #{orderId} was placed"
}
});
export const getActivityMessage = (
activity: Home_activities_edges_node,
intl: IntlShape
) => {
switch (activity.type) { switch (activity.type) {
case OrderEventsEnum.ORDER_FULLY_PAID: case OrderEventsEnum.ORDER_FULLY_PAID:
return i18n.t("Order #{{ orderId }} was fully paid", { return intl.formatMessage(messages.paid, {
orderId: activity.orderNumber orderId: activity.orderNumber
}); });
case OrderEventsEnum.PLACED: case OrderEventsEnum.PLACED:
return i18n.t("Order #{{ orderId }} was placed", { return intl.formatMessage(messages.placed, {
orderId: activity.orderNumber orderId: activity.orderNumber
}); });
case OrderEventsEnum.PLACED_FROM_DRAFT: case OrderEventsEnum.PLACED_FROM_DRAFT:
return i18n.t( return intl.formatMessage(messages.draft, {
"Order #{{ orderId }} was placed from draft by {{ user }}", orderId: activity.orderNumber,
{ userEmail: activity.user.email
orderId: activity.orderNumber, });
user: activity.user.email
}
);
default: default:
return activity.message; return activity.message;
} }

View file

@ -1,18 +0,0 @@
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import XHR from "i18next-xhr-backend";
i18n.use(XHR);
i18n.use(LanguageDetector);
i18n.init({
defaultNS: "dashboard",
fallbackLng: "en",
interpolation: {
escapeValue: false
},
keySeparator: false,
ns: ["dashboard"],
nsSeparator: false
});
export default i18n;

View file

@ -1,15 +1,24 @@
import { defineMessages } from "react-intl"; import { defineMessages, IntlShape } from "react-intl";
export const commonMessages = defineMessages({ export const commonMessages = defineMessages({
availability: { availability: {
defaultMessage: "Availability" defaultMessage: "Availability"
}, },
catalog: {
defaultMessage: "Catalog"
},
dashboard: { dashboard: {
defaultMessage: "Dashboard" defaultMessage: "Dashboard"
}, },
description: { description: {
defaultMessage: "Description" defaultMessage: "Description"
}, },
discounts: {
defaultMessage: "Discounts"
},
drafts: {
defaultMessage: "Drafts"
},
email: { email: {
defaultMessage: "E-mail Address" defaultMessage: "E-mail Address"
}, },
@ -28,6 +37,9 @@ export const commonMessages = defineMessages({
lastName: { lastName: {
defaultMessage: "Last Name" defaultMessage: "Last Name"
}, },
no: {
defaultMessage: "No"
},
optionalField: { optionalField: {
defaultMessage: "Optional", defaultMessage: "Optional",
description: "field is optional" description: "field is optional"
@ -50,6 +62,9 @@ export const commonMessages = defineMessages({
uploadImage: { uploadImage: {
defaultMessage: "Upload image", defaultMessage: "Upload image",
description: "button" description: "button"
},
yes: {
defaultMessage: "Yes"
} }
}); });
@ -121,6 +136,10 @@ export const sectionNames = defineMessages({
defaultMessage: "Draft Orders", defaultMessage: "Draft Orders",
description: "draft orders section name" description: "draft orders section name"
}, },
home: {
defaultMessage: "Home",
description: "home section name"
},
navigation: { navigation: {
defaultMessage: "Navigation", defaultMessage: "Navigation",
description: "navigation section name" description: "navigation section name"
@ -170,3 +189,9 @@ export const sectionNames = defineMessages({
description: "vouchers section name" description: "vouchers section name"
} }
}); });
export function translateBoolean(value: boolean, intl: IntlShape): string {
return value
? intl.formatMessage(commonMessages.yes)
: intl.formatMessage(commonMessages.no);
}

View file

@ -2,10 +2,10 @@ import moment from "moment-timezone";
import { MutationFunction, MutationResult } from "react-apollo"; import { MutationFunction, MutationResult } from "react-apollo";
import urlJoin from "url-join"; import urlJoin from "url-join";
import { defineMessages, IntlShape } from "react-intl";
import { ConfirmButtonTransitionState } from "./components/ConfirmButton/ConfirmButton"; import { ConfirmButtonTransitionState } from "./components/ConfirmButton/ConfirmButton";
import { APP_MOUNT_URI } from "./config"; import { APP_MOUNT_URI } from "./config";
import { AddressType } from "./customers/types"; import { AddressType } from "./customers/types";
import i18n from "./i18n";
import { PartialMutationProviderOutput, UserError } from "./types"; import { PartialMutationProviderOutput, UserError } from "./types";
import { import {
AuthorizationKeyType, AuthorizationKeyType,
@ -26,7 +26,7 @@ export type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<
> & > &
{ {
[K in Keys]-?: Required<Pick<T, K>> & [K in Keys]-?: Required<Pick<T, K>> &
Partial<Record<Exclude<Keys, K>, undefined>> Partial<Record<Exclude<Keys, K>, undefined>>;
}[Keys]; }[Keys];
export function renderCollection<T>( export function renderCollection<T>(
@ -57,33 +57,109 @@ export function decimal(value: string | number) {
export const removeDoubleSlashes = (url: string) => export const removeDoubleSlashes = (url: string) =>
url.replace(/([^:]\/)\/+/g, "$1"); url.replace(/([^:]\/)\/+/g, "$1");
export const transformPaymentStatus = (status: string) => { const paymentStatusMessages = defineMessages({
paid: {
defaultMessage: "Fully paid",
description: "payment status"
},
partiallyPaid: {
defaultMessage: "Partially paid",
description: "payment status"
},
partiallyRefunded: {
defaultMessage: "Partially refunded",
description: "payment status"
},
refunded: {
defaultMessage: "Fully refunded",
description: "payment status"
},
unpaid: {
defaultMessage: "Unpaid",
description: "payment status"
}
});
export const transformPaymentStatus = (status: string, intl: IntlShape) => {
switch (status) { switch (status) {
case PaymentChargeStatusEnum.PARTIALLY_CHARGED: case PaymentChargeStatusEnum.PARTIALLY_CHARGED:
return { localized: i18n.t("Partially paid"), status: "error" }; return {
localized: intl.formatMessage(paymentStatusMessages.partiallyPaid),
status: "error"
};
case PaymentChargeStatusEnum.FULLY_CHARGED: case PaymentChargeStatusEnum.FULLY_CHARGED:
return { localized: i18n.t("Fully paid"), status: "success" }; return {
localized: intl.formatMessage(paymentStatusMessages.paid),
status: "success"
};
case PaymentChargeStatusEnum.PARTIALLY_REFUNDED: case PaymentChargeStatusEnum.PARTIALLY_REFUNDED:
return { localized: i18n.t("Partially refunded"), status: "error" }; return {
localized: intl.formatMessage(paymentStatusMessages.partiallyRefunded),
status: "error"
};
case PaymentChargeStatusEnum.FULLY_REFUNDED: case PaymentChargeStatusEnum.FULLY_REFUNDED:
return { localized: i18n.t("Fully refunded"), status: "success" }; return {
localized: intl.formatMessage(paymentStatusMessages.refunded),
status: "success"
};
default: default:
return { localized: i18n.t("Unpaid"), status: "error" }; return {
localized: intl.formatMessage(paymentStatusMessages.unpaid),
status: "error"
};
} }
}; };
export const transformOrderStatus = (status: string) => { const orderStatusMessages = defineMessages({
cancelled: {
defaultMessage: "Cancelled",
description: "order status"
},
draft: {
defaultMessage: "Draft",
description: "order status"
},
fulfilled: {
defaultMessage: "Fulfilled",
description: "order status"
},
partiallyFulfilled: {
defaultMessage: "Partially fulfilled",
description: "order status"
},
unfulfilled: {
defaultMessage: "Unfulfilled",
description: "order status"
}
});
export const transformOrderStatus = (status: string, intl: IntlShape) => {
switch (status) { switch (status) {
case OrderStatus.FULFILLED: case OrderStatus.FULFILLED:
return { localized: i18n.t("Fulfilled"), status: "success" }; return {
localized: intl.formatMessage(orderStatusMessages.fulfilled),
status: "success"
};
case OrderStatus.PARTIALLY_FULFILLED: case OrderStatus.PARTIALLY_FULFILLED:
return { localized: i18n.t("Partially fulfilled"), status: "neutral" }; return {
localized: intl.formatMessage(orderStatusMessages.partiallyFulfilled),
status: "neutral"
};
case OrderStatus.UNFULFILLED: case OrderStatus.UNFULFILLED:
return { localized: i18n.t("Unfulfilled"), status: "error" }; return {
localized: intl.formatMessage(orderStatusMessages.unfulfilled),
status: "error"
};
case OrderStatus.CANCELED: case OrderStatus.CANCELED:
return { localized: i18n.t("Cancelled"), status: "error" }; return {
localized: intl.formatMessage(orderStatusMessages.cancelled),
status: "error"
};
case OrderStatus.DRAFT: case OrderStatus.DRAFT:
return { localized: i18n.t("Draft"), status: "error" }; return {
localized: intl.formatMessage(orderStatusMessages.draft),
status: "error"
};
} }
return { return {
localized: status, localized: status,
@ -105,44 +181,163 @@ export const transformAddressToForm = (data: AddressType) => ({
streetAddress2: maybe(() => data.streetAddress2, "") streetAddress2: maybe(() => data.streetAddress2, "")
}); });
export const translatedTaxRates = () => ({ const taxRatesMessages = defineMessages({
[TaxRateType.ACCOMMODATION]: i18n.t("Accommodation"), accommodation: {
[TaxRateType.ADMISSION_TO_CULTURAL_EVENTS]: i18n.t( defaultMessage: "Accommodation",
"Admission to cultural events" description: "tax rate"
), },
[TaxRateType.ADMISSION_TO_ENTERTAINMENT_EVENTS]: i18n.t( admissionToCulturalEvents: {
"Admission to entertainment events" defaultMessage: "Admission to cultural events",
), description: "tax rate"
[TaxRateType.ADMISSION_TO_SPORTING_EVENTS]: i18n.t( },
"Admission to sporting events" admissionToEntertainmentEvents: {
), defaultMessage: "Admission to entertainment events",
[TaxRateType.ADVERTISING]: i18n.t("Advertising"), description: "tax rate"
[TaxRateType.AGRICULTURAL_SUPPLIES]: i18n.t("Agricultural supplies"), },
[TaxRateType.BABY_FOODSTUFFS]: i18n.t("Baby foodstuffs"), admissionToSportingEvents: {
[TaxRateType.BIKES]: i18n.t("Bikes"), defaultMessage: "Admission to sporting events",
[TaxRateType.BOOKS]: i18n.t("Books"), description: "tax rate"
[TaxRateType.CHILDRENS_CLOTHING]: i18n.t("Children's clothing"), },
[TaxRateType.DOMESTIC_FUEL]: i18n.t("Domestic fuel"), advertising: {
[TaxRateType.DOMESTIC_SERVICES]: i18n.t("Domestic services"), defaultMessage: "Advertising",
[TaxRateType.E_BOOKS]: i18n.t("E-books"), description: "tax rate"
[TaxRateType.FOODSTUFFS]: i18n.t("Foodstuffs"), },
[TaxRateType.HOTELS]: i18n.t("Hotels"), agriculturalSupplies: {
[TaxRateType.MEDICAL]: i18n.t("Medical"), defaultMessage: "Agricultural supplies",
[TaxRateType.NEWSPAPERS]: i18n.t("Newspapers"), description: "tax rate"
[TaxRateType.PASSENGER_TRANSPORT]: i18n.t("Passenger transport"), },
[TaxRateType.PHARMACEUTICALS]: i18n.t("Pharmaceuticals"), babyFoodstuffs: {
[TaxRateType.PROPERTY_RENOVATIONS]: i18n.t("Property renovations"), defaultMessage: "Baby foodstuffs",
[TaxRateType.RESTAURANTS]: i18n.t("Restaurants"), description: "tax rate"
[TaxRateType.SOCIAL_HOUSING]: i18n.t("Social housing"), },
[TaxRateType.STANDARD]: i18n.t("Standard"), bikes: {
[TaxRateType.WATER]: i18n.t("Water") defaultMessage: "Bikes",
description: "tax rate"
},
books: {
defaultMessage: "Books",
description: "tax rate"
},
childrensClothing: {
defaultMessage: "Children's clothing",
description: "tax rate"
},
domesticFuel: {
defaultMessage: "Domestic fuel",
description: "tax rate"
},
domesticServices: {
defaultMessage: "Domestic services",
description: "tax rate"
},
ebooks: {
defaultMessage: "E-books",
description: "tax rate"
},
foodstuffs: {
defaultMessage: "Foodstuffs",
description: "tax rate"
},
hotels: {
defaultMessage: "Hotels",
description: "tax rate"
},
medical: {
defaultMessage: "Medical",
description: "tax rate"
},
newspapers: {
defaultMessage: "Newspapers",
description: "tax rate"
},
passengerTransport: {
defaultMessage: "Passenger transport",
description: "tax rate"
},
pharmaceuticals: {
defaultMessage: "Pharmaceuticals",
description: "tax rate"
},
propertyRenovations: {
defaultMessage: "Property renovations",
description: "tax rate"
},
restaurants: {
defaultMessage: "Restaurants",
description: "tax rate"
},
socialHousing: {
defaultMessage: "Social housing",
description: "tax rate"
},
standard: {
defaultMessage: "Standard",
description: "tax rate"
},
water: {
defaultMessage: "Water",
description: "tax rate"
}
}); });
export const translatedAuthorizationKeyTypes = () => ({ export const translatedTaxRates = (intl: IntlShape) => ({
[AuthorizationKeyType.FACEBOOK]: i18n.t("Facebook"), [TaxRateType.ACCOMMODATION]: intl.formatMessage(
[AuthorizationKeyType.GOOGLE_OAUTH2]: i18n.t("Google OAuth2") taxRatesMessages.accommodation
),
[TaxRateType.ADMISSION_TO_CULTURAL_EVENTS]: intl.formatMessage(
taxRatesMessages.admissionToCulturalEvents
),
[TaxRateType.ADMISSION_TO_ENTERTAINMENT_EVENTS]: intl.formatMessage(
taxRatesMessages.admissionToEntertainmentEvents
),
[TaxRateType.ADMISSION_TO_SPORTING_EVENTS]: intl.formatMessage(
taxRatesMessages.admissionToSportingEvents
),
[TaxRateType.ADVERTISING]: intl.formatMessage(taxRatesMessages.advertising),
[TaxRateType.AGRICULTURAL_SUPPLIES]: intl.formatMessage(
taxRatesMessages.agriculturalSupplies
),
[TaxRateType.BABY_FOODSTUFFS]: intl.formatMessage(
taxRatesMessages.babyFoodstuffs
),
[TaxRateType.BIKES]: intl.formatMessage(taxRatesMessages.bikes),
[TaxRateType.BOOKS]: intl.formatMessage(taxRatesMessages.books),
[TaxRateType.CHILDRENS_CLOTHING]: intl.formatMessage(
taxRatesMessages.childrensClothing
),
[TaxRateType.DOMESTIC_FUEL]: intl.formatMessage(
taxRatesMessages.domesticFuel
),
[TaxRateType.DOMESTIC_SERVICES]: intl.formatMessage(
taxRatesMessages.domesticServices
),
[TaxRateType.E_BOOKS]: intl.formatMessage(taxRatesMessages.ebooks),
[TaxRateType.FOODSTUFFS]: intl.formatMessage(taxRatesMessages.foodstuffs),
[TaxRateType.HOTELS]: intl.formatMessage(taxRatesMessages.hotels),
[TaxRateType.MEDICAL]: intl.formatMessage(taxRatesMessages.medical),
[TaxRateType.NEWSPAPERS]: intl.formatMessage(taxRatesMessages.newspapers),
[TaxRateType.PASSENGER_TRANSPORT]: intl.formatMessage(
taxRatesMessages.passengerTransport
),
[TaxRateType.PHARMACEUTICALS]: intl.formatMessage(
taxRatesMessages.pharmaceuticals
),
[TaxRateType.PROPERTY_RENOVATIONS]: intl.formatMessage(
taxRatesMessages.propertyRenovations
),
[TaxRateType.RESTAURANTS]: intl.formatMessage(taxRatesMessages.restaurants),
[TaxRateType.SOCIAL_HOUSING]: intl.formatMessage(
taxRatesMessages.socialHousing
),
[TaxRateType.STANDARD]: intl.formatMessage(taxRatesMessages.standard),
[TaxRateType.WATER]: intl.formatMessage(taxRatesMessages.water)
}); });
export const authorizationKeyTypes = {
[AuthorizationKeyType.FACEBOOK]: "Facebook",
[AuthorizationKeyType.GOOGLE_OAUTH2]: "Google OAuth2"
};
export function maybe<T>(exp: () => T): T | undefined; export function maybe<T>(exp: () => T): T | undefined;
export function maybe<T>(exp: () => T, d: T): T; export function maybe<T>(exp: () => T, d: T): T;
export function maybe(exp: any, d?: any) { export function maybe(exp: any, d?: any) {

View file

@ -2,9 +2,9 @@ import { ApolloError, MutationUpdaterFn } from "apollo-client";
import { DocumentNode } from "graphql"; import { DocumentNode } from "graphql";
import React from "react"; import React from "react";
import { Mutation, MutationFunction, MutationResult } from "react-apollo"; import { Mutation, MutationFunction, MutationResult } from "react-apollo";
import { useIntl } from "react-intl";
import useNotifier from "./hooks/useNotifier"; import useNotifier from "./hooks/useNotifier";
import i18n from "./i18n";
export interface TypedMutationInnerProps<TData, TVariables> { export interface TypedMutationInnerProps<TData, TVariables> {
children: ( children: (
@ -23,6 +23,7 @@ export function TypedMutation<TData, TVariables>(
) { ) {
return (props: TypedMutationInnerProps<TData, TVariables>) => { return (props: TypedMutationInnerProps<TData, TVariables>) => {
const notify = useNotifier(); const notify = useNotifier();
const intl = useIntl();
const { children, onCompleted, onError, variables } = props; const { children, onCompleted, onError, variables } = props;
return ( return (
@ -30,9 +31,15 @@ export function TypedMutation<TData, TVariables>(
mutation={mutation} mutation={mutation}
onCompleted={onCompleted} onCompleted={onCompleted}
onError={err => { onError={err => {
const msg = i18n.t("Something went wrong: {{ message }}", { const msg = intl.formatMessage(
message: err.message {
}); defaultMessage: "Something went wrong. {errorMessage}",
description: "error message"
},
{
errorMessage: err.message
}
);
notify({ text: msg }); notify({ text: msg });
if (onError) { if (onError) {
onError(err); onError(err);

View file

@ -136,13 +136,13 @@ const MenuDetails: React.FC<MenuDetailsProps> = ({ id, params }) => {
return ( return (
<MenuDeleteMutation <MenuDeleteMutation
onCompleted={data => onCompleted={data =>
handleDelete(data, navigate, notify) handleDelete(data, navigate, notify, intl)
} }
> >
{(menuDelete, menuDeleteOpts) => ( {(menuDelete, menuDeleteOpts) => (
<MenuUpdateMutation <MenuUpdateMutation
onCompleted={data => onCompleted={data =>
handleUpdate(data, notify, refetch) handleUpdate(data, notify, refetch, intl)
} }
> >
{(menuUpdate, menuUpdateOpts) => { {(menuUpdate, menuUpdateOpts) => {
@ -263,7 +263,12 @@ const MenuDetails: React.FC<MenuDetailsProps> = ({ id, params }) => {
<MenuItemCreateMutation <MenuItemCreateMutation
onCompleted={data => onCompleted={data =>
handleItemCreate(data, notify, closeModal) handleItemCreate(
data,
notify,
closeModal,
intl
)
} }
> >
{(menuItemCreate, menuItemCreateOpts) => { {(menuItemCreate, menuItemCreateOpts) => {
@ -323,7 +328,8 @@ const MenuDetails: React.FC<MenuDetailsProps> = ({ id, params }) => {
data, data,
id, id,
navigate, navigate,
notify notify,
intl
) )
} }
> >

View file

@ -1,6 +1,8 @@
import { IntlShape } from "react-intl";
import { commonMessages } from "@saleor/intl";
import { UseNavigatorResult } from "../../../hooks/useNavigator"; import { UseNavigatorResult } from "../../../hooks/useNavigator";
import { UseNotifierResult } from "../../../hooks/useNotifier"; import { UseNotifierResult } from "../../../hooks/useNotifier";
import i18n from "../../../i18n";
import { MenuDelete } from "../../types/MenuDelete"; import { MenuDelete } from "../../types/MenuDelete";
import { MenuItemCreate } from "../../types/MenuItemCreate"; import { MenuItemCreate } from "../../types/MenuItemCreate";
import { MenuItemUpdate } from "../../types/MenuItemUpdate"; import { MenuItemUpdate } from "../../types/MenuItemUpdate";
@ -10,14 +12,13 @@ import { menuListUrl, menuUrl } from "../../urls";
export function handleItemCreate( export function handleItemCreate(
data: MenuItemCreate, data: MenuItemCreate,
notify: UseNotifierResult, notify: UseNotifierResult,
closeModal: () => void closeModal: () => void,
intl: IntlShape
) { ) {
if (data.menuItemCreate.errors.length === 0) { if (data.menuItemCreate.errors.length === 0) {
closeModal(); closeModal();
notify({ notify({
text: i18n.t("Created menu item", { text: intl.formatMessage(commonMessages.savedChanges)
context: "notification"
})
}); });
} }
} }
@ -26,13 +27,12 @@ export function handleItemUpdate(
data: MenuItemUpdate, data: MenuItemUpdate,
id: string, id: string,
navigate: UseNavigatorResult, navigate: UseNavigatorResult,
notify: UseNotifierResult notify: UseNotifierResult,
intl: IntlShape
) { ) {
if (data.menuItemUpdate.errors.length === 0) { if (data.menuItemUpdate.errors.length === 0) {
notify({ notify({
text: i18n.t("Updated menu item", { text: intl.formatMessage(commonMessages.savedChanges)
context: "notification"
})
}); });
navigate( navigate(
menuUrl(id, { menuUrl(id, {
@ -46,13 +46,12 @@ export function handleItemUpdate(
export function handleDelete( export function handleDelete(
data: MenuDelete, data: MenuDelete,
navigate: UseNavigatorResult, navigate: UseNavigatorResult,
notify: UseNotifierResult notify: UseNotifierResult,
intl: IntlShape
) { ) {
if (data.menuDelete.errors.length === 0) { if (data.menuDelete.errors.length === 0) {
notify({ notify({
text: i18n.t("Removed menu", { text: intl.formatMessage(commonMessages.savedChanges)
context: "notification"
})
}); });
navigate(menuListUrl(), true); navigate(menuListUrl(), true);
} }
@ -61,7 +60,8 @@ export function handleDelete(
export function handleUpdate( export function handleUpdate(
data: MenuUpdate, data: MenuUpdate,
notify: UseNotifierResult, notify: UseNotifierResult,
refetch: () => void refetch: () => void,
intl: IntlShape
) { ) {
if ( if (
data.menuItemBulkDelete.errors.length === 0 && data.menuItemBulkDelete.errors.length === 0 &&
@ -69,9 +69,7 @@ export function handleUpdate(
data.menuUpdate.errors.length === 0 data.menuUpdate.errors.length === 0
) { ) {
notify({ notify({
text: i18n.t("Updated menu", { text: intl.formatMessage(commonMessages.savedChanges)
context: "notification"
})
}); });
refetch(); refetch();
} }

View file

@ -10,7 +10,7 @@ import TableCell from "@material-ui/core/TableCell";
import TableFooter from "@material-ui/core/TableFooter"; import TableFooter from "@material-ui/core/TableFooter";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import Checkbox from "@saleor/components/Checkbox"; import Checkbox from "@saleor/components/Checkbox";
import { DateTime } from "@saleor/components/Date"; import { DateTime } from "@saleor/components/Date";
@ -78,11 +78,13 @@ export const OrderDraftList = withStyles(styles, { name: "OrderDraftList" })(
toggleAll, toggleAll,
toolbar toolbar
}: OrderDraftListProps) => { }: OrderDraftListProps) => {
const intl = useIntl();
const orderDraftList = orders const orderDraftList = orders
? orders.map(order => ({ ? orders.map(order => ({
...order, ...order,
paymentStatus: transformPaymentStatus(order.paymentStatus), paymentStatus: transformPaymentStatus(order.paymentStatus, intl),
status: transformOrderStatus(order.status) status: transformOrderStatus(order.status, intl)
})) }))
: undefined; : undefined;

View file

@ -10,7 +10,7 @@ import TableCell from "@material-ui/core/TableCell";
import TableFooter from "@material-ui/core/TableFooter"; import TableFooter from "@material-ui/core/TableFooter";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import Checkbox from "@saleor/components/Checkbox"; import Checkbox from "@saleor/components/Checkbox";
import { DateTime } from "@saleor/components/Date"; import { DateTime } from "@saleor/components/Date";
@ -85,11 +85,13 @@ export const OrderList = withStyles(styles, { name: "OrderList" })(
toggleAll, toggleAll,
toolbar toolbar
}: OrderListProps) => { }: OrderListProps) => {
const intl = useIntl();
const orderList = orders const orderList = orders
? orders.map(order => ({ ? orders.map(order => ({
...order, ...order,
paymentStatus: transformPaymentStatus(order.paymentStatus), paymentStatus: transformPaymentStatus(order.paymentStatus, intl),
status: transformOrderStatus(order.status) status: transformOrderStatus(order.status, intl)
})) }))
: undefined; : undefined;
return ( return (

View file

@ -64,7 +64,10 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })(
const canMarkAsPaid = maybe(() => order.actions, []).includes( const canMarkAsPaid = maybe(() => order.actions, []).includes(
OrderAction.MARK_AS_PAID OrderAction.MARK_AS_PAID
); );
const payment = transformPaymentStatus(maybe(() => order.paymentStatus)); const payment = transformPaymentStatus(
maybe(() => order.paymentStatus),
intl
);
return ( return (
<Card> <Card>
<CardTitle <CardTitle

View file

@ -1,3 +1,4 @@
import { MessageDescriptor } from "react-intl";
import { SearchCustomers_customers_edges_node } from "../containers/SearchCustomers/types/SearchCustomers"; import { SearchCustomers_customers_edges_node } from "../containers/SearchCustomers/types/SearchCustomers";
import { transformOrderStatus, transformPaymentStatus } from "../misc"; import { transformOrderStatus, transformPaymentStatus } from "../misc";
import { import {
@ -1126,8 +1127,12 @@ export const draftOrder = (placeholder: string): OrderDetails_order => ({
}); });
export const flatOrders = orders.map(order => ({ export const flatOrders = orders.map(order => ({
...order, ...order,
orderStatus: transformOrderStatus(order.status), orderStatus: transformOrderStatus(order.status, {
paymentStatus: transformPaymentStatus(order.paymentStatus) formatMessage: (message: MessageDescriptor) => message.defaultMessage
} as any),
paymentStatus: transformPaymentStatus(order.paymentStatus, {
formatMessage: (message: MessageDescriptor) => message.defaultMessage
} as any)
})); }));
export const variants = [ export const variants = [
{ id: "p1", name: "Product 1: variant 1", sku: "12345", stockQuantity: 3 }, { id: "p1", name: "Product 1: variant 1", sku: "12345", stockQuantity: 3 },

View file

@ -199,7 +199,8 @@ export const OrderList: React.StatelessComponent<OrderListProps> = ({
{ {
formatDate formatDate
}, },
changeFilterField changeFilterField,
intl
)} )}
currentTab={currentTab} currentTab={currentTab}
disabled={loading} disabled={loading}

View file

@ -1,6 +1,7 @@
import { defineMessages, IntlShape } from "react-intl";
import { FilterContentSubmitData } from "../../../components/Filter"; import { FilterContentSubmitData } from "../../../components/Filter";
import { Filter } from "../../../components/TableFilter"; import { Filter } from "../../../components/TableFilter";
import i18n from "../../../i18n";
import { import {
OrderFilterInput, OrderFilterInput,
OrderStatusFilter OrderStatusFilter
@ -18,16 +19,43 @@ import {
export const ORDER_FILTERS_KEY = "orderFilters"; export const ORDER_FILTERS_KEY = "orderFilters";
function getStatusLabel(status: string): string { const filterMessages = defineMessages({
dateFrom: {
defaultMessage: "Date from {date}",
description: "filter by date"
},
dateIs: {
defaultMessage: "Date is {date}",
description: "filter by date"
},
dateTo: {
defaultMessage: "Date to {date}",
description: "filter by date"
},
fulfilled: {
defaultMessage: "Fulfilled",
description: "order status"
},
partiallyFulfilled: {
defaultMessage: "Partially Fulfilled",
description: "order status"
},
unfulfilled: {
defaultMessage: "Unfulfilled",
description: "order status"
}
});
function getStatusLabel(status: string, intl: IntlShape): string {
switch (status) { switch (status) {
case OrderStatusFilter.FULFILLED.toString(): case OrderStatusFilter.FULFILLED.toString():
return i18n.t("Fulfilled"); return intl.formatMessage(filterMessages.fulfilled);
case OrderStatusFilter.PARTIALLY_FULFILLED.toString(): case OrderStatusFilter.PARTIALLY_FULFILLED.toString():
return i18n.t("Partially Fulfilled"); return intl.formatMessage(filterMessages.partiallyFulfilled);
case OrderStatusFilter.UNFULFILLED.toString(): case OrderStatusFilter.UNFULFILLED.toString():
return i18n.t("Unfulfilled"); return intl.formatMessage(filterMessages.unfulfilled);
} }
return ""; return "";
@ -90,7 +118,8 @@ interface OrderListChipFormatData {
export function createFilterChips( export function createFilterChips(
filters: OrderListUrlFilters, filters: OrderListUrlFilters,
formatData: OrderListChipFormatData, formatData: OrderListChipFormatData,
onFilterDelete: (filters: OrderListUrlFilters) => void onFilterDelete: (filters: OrderListUrlFilters) => void,
intl: IntlShape
): Filter[] { ): Filter[] {
let filterChips: Filter[] = []; let filterChips: Filter[] = [];
@ -99,7 +128,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: i18n.t("Date is {{ date }}", { label: intl.formatMessage(filterMessages.dateIs, {
date: formatData.formatDate(filters.dateFrom) date: formatData.formatDate(filters.dateFrom)
}), }),
onClick: () => onClick: () =>
@ -115,7 +144,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: i18n.t("Date from {{ date }}", { label: intl.formatMessage(filterMessages.dateFrom, {
date: formatData.formatDate(filters.dateFrom) date: formatData.formatDate(filters.dateFrom)
}), }),
onClick: () => onClick: () =>
@ -131,7 +160,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: i18n.t("Date to {{ date }}", { label: intl.formatMessage(filterMessages.dateTo, {
date: formatData.formatDate(filters.dateTo) date: formatData.formatDate(filters.dateTo)
}), }),
onClick: () => onClick: () =>
@ -149,7 +178,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: getStatusLabel(filters.status), label: getStatusLabel(filters.status, intl),
onClick: () => onClick: () =>
onFilterDelete({ onFilterDelete({
...filters, ...filters,

View file

@ -217,7 +217,8 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
currencySymbol, currencySymbol,
locale locale
}, },
changeFilterField changeFilterField,
intl
)} )}
onAdd={() => navigate(productAddUrl)} onAdd={() => navigate(productAddUrl)}
disabled={loading} disabled={loading}

View file

@ -1,6 +1,6 @@
import { defineMessages, IntlShape } from "react-intl";
import { FilterContentSubmitData } from "../../../components/Filter"; import { FilterContentSubmitData } from "../../../components/Filter";
import { Filter } from "../../../components/TableFilter"; import { Filter } from "../../../components/TableFilter";
import i18n from "../../../i18n";
import { import {
ProductFilterInput, ProductFilterInput,
StockAvailability StockAvailability
@ -61,6 +61,37 @@ export function createFilter(
} }
} }
const filterMessages = defineMessages({
available: {
defaultMessage: "Available",
description: "filter products by stock"
},
hidden: {
defaultMessage: "Hidden",
description: "filter products by visibility"
},
outOfStock: {
defaultMessage: "Out of stock",
description: "filter products by stock"
},
priceFrom: {
defaultMessage: "Price from {price}",
description: "filter by price"
},
priceIs: {
defaultMessage: "Price is {price}",
description: "filter by price"
},
priceTo: {
defaultMessage: "Price to {price}",
description: "filter by price"
},
published: {
defaultMessage: "Published",
description: "filter products by visibility"
}
});
interface ProductListChipFormatData { interface ProductListChipFormatData {
currencySymbol: string; currencySymbol: string;
locale: string; locale: string;
@ -68,7 +99,8 @@ interface ProductListChipFormatData {
export function createFilterChips( export function createFilterChips(
filters: ProductListUrlFilters, filters: ProductListUrlFilters,
formatData: ProductListChipFormatData, formatData: ProductListChipFormatData,
onFilterDelete: (filters: ProductListUrlFilters) => void onFilterDelete: (filters: ProductListUrlFilters) => void,
intl: IntlShape
): Filter[] { ): Filter[] {
let filterChips: Filter[] = []; let filterChips: Filter[] = [];
@ -77,7 +109,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: i18n.t("Price is {{ price }}", { label: intl.formatMessage(filterMessages.priceIs, {
price: parseFloat(filters.priceFrom).toLocaleString( price: parseFloat(filters.priceFrom).toLocaleString(
formatData.locale, formatData.locale,
{ {
@ -99,7 +131,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: i18n.t("Price from {{ price }}", { label: intl.formatMessage(filterMessages.priceFrom, {
price: parseFloat(filters.priceFrom).toLocaleString( price: parseFloat(filters.priceFrom).toLocaleString(
formatData.locale, formatData.locale,
{ {
@ -121,7 +153,7 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: i18n.t("Price to {{ price }}", { label: intl.formatMessage(filterMessages.priceTo, {
price: parseFloat(filters.priceTo).toLocaleString( price: parseFloat(filters.priceTo).toLocaleString(
formatData.locale, formatData.locale,
{ {
@ -147,8 +179,8 @@ export function createFilterChips(
{ {
label: label:
filters.status === StockAvailability.IN_STOCK.toString() filters.status === StockAvailability.IN_STOCK.toString()
? i18n.t("Available") ? intl.formatMessage(filterMessages.available)
: i18n.t("Out Of Stock"), : intl.formatMessage(filterMessages.outOfStock),
onClick: () => onClick: () =>
onFilterDelete({ onFilterDelete({
...filters, ...filters,
@ -162,10 +194,9 @@ export function createFilterChips(
filterChips = [ filterChips = [
...filterChips, ...filterChips,
{ {
label: label: !!filters.isPublished
filters.isPublished === StockAvailability.IN_STOCK.toString() ? intl.formatMessage(filterMessages.published)
? i18n.t("Published") : intl.formatMessage(filterMessages.hidden),
: i18n.t("Hidden"),
onClick: () => onClick: () =>
onFilterDelete({ onFilterDelete({
...filters, ...filters,

View file

@ -3,12 +3,12 @@ import { DocumentNode } from "graphql";
import gql from "graphql-tag"; import gql from "graphql-tag";
import React from "react"; import React from "react";
import { Query, QueryResult } from "react-apollo"; import { Query, QueryResult } from "react-apollo";
import { useIntl } from "react-intl";
import AppProgress from "./components/AppProgress"; import AppProgress from "./components/AppProgress";
import ErrorPage from "./components/ErrorPage/ErrorPage"; import ErrorPage from "./components/ErrorPage/ErrorPage";
import useNavigator from "./hooks/useNavigator"; import useNavigator from "./hooks/useNavigator";
import useNotifier from "./hooks/useNotifier"; import useNotifier from "./hooks/useNotifier";
import i18n from "./i18n";
import { RequireAtLeastOne } from "./misc"; import { RequireAtLeastOne } from "./misc";
export interface LoadMore<TData, TVariables> { export interface LoadMore<TData, TVariables> {
@ -69,6 +69,7 @@ export function TypedQuery<TData, TVariables>(
return ({ children, displayLoader, skip, variables, require }) => { return ({ children, displayLoader, skip, variables, require }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const pushMessage = useNotifier(); const pushMessage = useNotifier();
const intl = useIntl();
return ( return (
<AppProgress> <AppProgress>
@ -82,9 +83,15 @@ export function TypedQuery<TData, TVariables>(
> >
{queryData => { {queryData => {
if (queryData.error) { if (queryData.error) {
const msg = i18n.t("Something went wrong: {{ message }}", { const msg = intl.formatMessage(
message: queryData.error.message {
}); defaultMessage: "Something went wrong. {errorMessage}",
description: "error message"
},
{
message: queryData.error.message
}
);
pushMessage({ text: msg }); pushMessage({ text: msg });
} }

View file

@ -11,7 +11,7 @@ import Form, { FormProps } from "@saleor/components/Form";
import { FormSpacer } from "@saleor/components/FormSpacer"; import { FormSpacer } from "@saleor/components/FormSpacer";
import SingleSelectField from "@saleor/components/SingleSelectField"; import SingleSelectField from "@saleor/components/SingleSelectField";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { translatedAuthorizationKeyTypes } from "../../../misc"; import { authorizationKeyTypes } from "../../../misc";
import { AuthorizationKeyType } from "../../../types/globalTypes"; import { AuthorizationKeyType } from "../../../types/globalTypes";
export interface SiteSettingsKeyDialogForm { export interface SiteSettingsKeyDialogForm {
@ -33,7 +33,6 @@ const SiteSettingsKeyDialog: React.StatelessComponent<
SiteSettingsKeyDialogProps SiteSettingsKeyDialogProps
> = ({ errors, initial, open, onClose, onSubmit }) => { > = ({ errors, initial, open, onClose, onSubmit }) => {
const intl = useIntl(); const intl = useIntl();
const keyTypes = translatedAuthorizationKeyTypes();
return ( return (
<Dialog onClose={onClose} maxWidth="xs" open={open}> <Dialog onClose={onClose} maxWidth="xs" open={open}>
@ -48,8 +47,8 @@ const SiteSettingsKeyDialog: React.StatelessComponent<
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
<SingleSelectField <SingleSelectField
choices={Object.keys(keyTypes).map(key => ({ choices={Object.keys(authorizationKeyTypes).map(key => ({
label: keyTypes[key], label: authorizationKeyTypes[key],
value: key value: key
}))} }))}
error={!!errors.keyType} error={!!errors.keyType}

View file

@ -18,11 +18,7 @@ import { FormattedMessage, useIntl } from "react-intl";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import { import { authorizationKeyTypes, maybe, renderCollection } from "../../../misc";
maybe,
renderCollection,
translatedAuthorizationKeyTypes
} from "../../../misc";
import { ICONBUTTON_SIZE } from "../../../theme"; import { ICONBUTTON_SIZE } from "../../../theme";
import { AuthorizationKeyType } from "../../../types/globalTypes"; import { AuthorizationKeyType } from "../../../types/globalTypes";
import { SiteSettings_shop_authorizationKeys } from "../../types/SiteSettings"; import { SiteSettings_shop_authorizationKeys } from "../../types/SiteSettings";
@ -48,8 +44,6 @@ const SiteSettingsKeys = withStyles(styles, { name: "SiteSettingsKeys" })(
({ classes, disabled, keys, onAdd, onRemove }: SiteSettingsKeysProps) => { ({ classes, disabled, keys, onAdd, onRemove }: SiteSettingsKeysProps) => {
const intl = useIntl(); const intl = useIntl();
const keyTypes = translatedAuthorizationKeyTypes();
return ( return (
<Card> <Card>
<CardTitle <CardTitle
@ -96,7 +90,7 @@ const SiteSettingsKeys = withStyles(styles, { name: "SiteSettingsKeys" })(
> >
<TableCell> <TableCell>
{maybe<React.ReactNode>( {maybe<React.ReactNode>(
() => keyTypes[key.name], () => authorizationKeyTypes[key.name],
<Skeleton /> <Skeleton />
)} )}
</TableCell> </TableCell>

View file

@ -11889,7 +11889,7 @@ exports[`Storyshots Views / Authentication / Log in default 1`] = `
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id" class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id"
data-shrink="false" data-shrink="false"
> >
Email E-mail Address
</label> </label>
<div <div
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id" class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id"
@ -12041,9 +12041,7 @@ exports[`Storyshots Views / Authentication / Log in error 1`] = `
<span <span
class="MuiTypography-root-id MuiTypography-caption-id" class="MuiTypography-root-id MuiTypography-caption-id"
> >
Sorry, your username and/or password are incorrect. Sorry, your username and/or password are incorrect. Please try again.
<br />
Please try again.
</span> </span>
</div> </div>
<div <div
@ -12053,7 +12051,7 @@ exports[`Storyshots Views / Authentication / Log in error 1`] = `
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id" class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id"
data-shrink="false" data-shrink="false"
> >
Email E-mail Address
</label> </label>
<div <div
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id" class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id"
@ -12206,7 +12204,7 @@ exports[`Storyshots Views / Authentication / Log in loading 1`] = `
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id" class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id"
data-shrink="false" data-shrink="false"
> >
Email E-mail Address
</label> </label>
<div <div
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id" class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id"
@ -42757,7 +42755,7 @@ exports[`Storyshots Views / Discounts / Voucher details default 1`] = `
<span <span
class="MuiTypography-root-id MuiTypography-body2-id MuiFormControlLabel-label-id" class="MuiTypography-root-id MuiTypography-body2-id MuiFormControlLabel-label-id"
> >
Specific Products Specific products
</span> </span>
</label> </label>
</div> </div>
@ -43736,7 +43734,7 @@ exports[`Storyshots Views / Discounts / Voucher details form errors 1`] = `
<span <span
class="MuiTypography-root-id MuiTypography-body2-id MuiFormControlLabel-label-id" class="MuiTypography-root-id MuiTypography-body2-id MuiFormControlLabel-label-id"
> >
Specific Products Specific products
</span> </span>
</label> </label>
</div> </div>
@ -44736,7 +44734,7 @@ exports[`Storyshots Views / Discounts / Voucher details loading 1`] = `
<span <span
class="MuiTypography-root-id MuiTypography-body2-id MuiFormControlLabel-label-id MuiFormControlLabel-disabled-id" class="MuiTypography-root-id MuiTypography-body2-id MuiFormControlLabel-label-id MuiFormControlLabel-disabled-id"
> >
Specific Products Specific products
</span> </span>
</label> </label>
</div> </div>

View file

@ -38,7 +38,7 @@ const CountryTaxesPage = withStyles(styles, { name: "CountryTaxesPage" })(
}: CountryTaxesPageProps & WithStyles<typeof styles>) => { }: CountryTaxesPageProps & WithStyles<typeof styles>) => {
const intl = useIntl(); const intl = useIntl();
const taxRates = translatedTaxRates(); const taxRates = translatedTaxRates(intl);
return ( return (
<Container> <Container>
<AppHeader onBack={onBack}> <AppHeader onBack={onBack}>

View file

@ -1,5 +0,0 @@
import i18n from "@saleor/i18n";
export function translateBoolean(value: boolean): string {
return value ? i18n.t("Yes") : i18n.t("No");
}