Refactor attribute section translations

This commit is contained in:
Dominik Żegleń 2019-08-16 13:47:30 +02:00 committed by dominik-zeglen
parent e574945972
commit a573f5e139
15 changed files with 559 additions and 320 deletions

41
package-lock.json generated
View file

@ -9397,7 +9397,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -9415,11 +9416,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -9432,15 +9435,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -9543,7 +9549,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -9553,6 +9560,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -9565,17 +9573,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -9592,6 +9603,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -9664,7 +9676,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -9674,6 +9687,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -9749,7 +9763,8 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -9779,6 +9794,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -9796,6 +9812,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -9834,11 +9851,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true
"bundled": true,
"optional": true
}
}
},

View file

@ -1,13 +1,13 @@
import DialogContentText from "@material-ui/core/DialogContentText";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import i18n from "../../../i18n";
export interface AttributeBulkDeleteDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
quantity: string;
quantity: number;
open: boolean;
onConfirm: () => void;
onClose: () => void;
@ -15,26 +15,38 @@ export interface AttributeBulkDeleteDialogProps {
const AttributeBulkDeleteDialog: React.StatelessComponent<
AttributeBulkDeleteDialogProps
> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => (
> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => {
const intl = useIntl();
return (
<ActionDialog
open={open}
confirmButtonState={confirmButtonState}
onClose={onClose}
onConfirm={onConfirm}
title={i18n.t("Remove attributes")}
title={intl.formatMessage({
defaultMessage: "Remove attributes",
description: "dialog title",
id: "attributeBulkDeleteDialogTitle"
})}
variant="delete"
>
<DialogContentText
dangerouslySetInnerHTML={{
__html: i18n.t(
"Are you sure you want to remove <strong>{{ quantity }}</strong> attributes?",
{
quantity
}
)
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to remove {counter, plural,
one {this attribute}
other {{displayQuantity} attributes}
}?"
description="dialog content"
id="attributeBulkDeleteDialogContent"
values={{
counter: quantity,
displayQuantity: <strong>{quantity}</strong>
}}
/>
</DialogContentText>
</ActionDialog>
);
};
AttributeBulkDeleteDialog.displayName = "AttributeBulkDeleteDialog";
export default AttributeBulkDeleteDialog;

View file

@ -1,9 +1,9 @@
import DialogContentText from "@material-ui/core/DialogContentText";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import i18n from "@saleor/i18n";
export interface AttributeDeleteDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
@ -19,27 +19,35 @@ const AttributeDeleteDialog: React.FC<AttributeDeleteDialogProps> = ({
onClose,
onConfirm,
open
}) => (
}) => {
const intl = useIntl();
return (
<ActionDialog
open={open}
onClose={onClose}
confirmButtonState={confirmButtonState}
onConfirm={onConfirm}
variant="delete"
title={i18n.t("Remove attribute")}
title={intl.formatMessage({
defaultMessage: "Remove attribute",
description: "dialog title",
id: "attributeDeleteDialogTitle"
})}
>
<DialogContentText
dangerouslySetInnerHTML={{
__html: i18n.t(
"Are you sure you want to remove <strong>{{ name }}</strong>?",
{
name
}
)
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to remove {name}?"
description="dialog content"
id="attributeDeleteDialogContent"
values={{
name: <strong>{name}</strong>
}}
/>
</DialogContentText>
</ActionDialog>
);
};
AttributeDeleteDialog.displayName = "AttributeDeleteDialog";
export default AttributeDeleteDialog;

View file

@ -2,13 +2,14 @@ import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import TextField from "@material-ui/core/TextField";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import slugify from "slugify";
import CardTitle from "@saleor/components/CardTitle";
import ControlledSwitch from "@saleor/components/ControlledSwitch";
import FormSpacer from "@saleor/components/FormSpacer";
import SingleSelectField from "@saleor/components/SingleSelectField";
import i18n from "@saleor/i18n";
import { commonMessages } from "@saleor/intl";
import { FormErrors } from "@saleor/types";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { AttributePageFormData } from "../AttributePage";
@ -21,31 +22,49 @@ export interface AttributeDetailsProps {
onChange: (event: React.ChangeEvent<any>) => void;
}
const inputTypeChoices = [
{
label: i18n.t("Dropdown"),
value: AttributeInputTypeEnum.DROPDOWN
},
{
label: i18n.t("Multiple Select"),
value: AttributeInputTypeEnum.MULTISELECT
}
];
const AttributeDetails: React.FC<AttributeDetailsProps> = ({
canChangeType,
data,
disabled,
errors,
onChange
}) => (
}) => {
const intl = useIntl();
const inputTypeChoices = [
{
label: intl.formatMessage({
defaultMessage: "Dropdown",
description: "attribute editor component type",
id: "attributeDetailsInputTypeDropdown"
}),
value: AttributeInputTypeEnum.DROPDOWN
},
{
label: intl.formatMessage({
defaultMessage: "Multiple Select",
description: "attribute editor component type",
id: "attributeDetailsInputTypeMultiselect"
}),
value: AttributeInputTypeEnum.MULTISELECT
}
];
return (
<Card>
<CardTitle title={i18n.t("General Information")} />
<CardTitle
title={
intl.formatMessage(commonMessages.generalInformations)
}
/>
<CardContent>
<TextField
disabled={disabled}
error={!!errors.name}
label={i18n.t("Default Label")}
label={intl.formatMessage({
defaultMessage: "Default Label",
description: "attribute label input field",
id: "attributeDetailsNameInputLabel"
})}
name={"name" as keyof AttributePageFormData}
fullWidth
helperText={errors.name}
@ -56,14 +75,21 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
<TextField
disabled={disabled}
error={!!errors.slug}
label={i18n.t("Attribute Code")}
label={intl.formatMessage({
defaultMessage: "Attribute Code",
description: "attribute slug input field",
id: "attributeDetailsSlugInputLabel"
})}
name={"slug" as keyof AttributePageFormData}
placeholder={slugify(data.name).toLowerCase()}
fullWidth
helperText={
errors.slug ||
i18n.t("This is used internally. Make sure you dont use spaces", {
context: "slug input"
intl.formatMessage({
defaultMessage:
"This is used internally. Make sure you dont use spaces",
description: "attribute slug input field helper text",
id: "attributeDetailsNameInputHelperText"
})
}
value={data.slug}
@ -75,8 +101,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
disabled={disabled || !canChangeType}
error={!!errors.inputType}
hint={errors.inputType}
label={i18n.t("Catalog Input type for Store Owner", {
context: "attribute input type"
label={intl.formatMessage({
defaultMessage: "Catalog Input type for Store Owner",
description: "attribute editor component type select field label",
id: "attributeDetailsInputTypeField"
})}
name="inputType"
onChange={onChange}
@ -85,8 +113,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
<FormSpacer />
<ControlledSwitch
checked={data.valueRequired}
label={i18n.t("Value Required", {
context: "attribute must have value"
label={intl.formatMessage({
defaultMessage: "Value Required",
description: "check to require attribute to have value",
id: "attributeDetailsValueRequiredInputLabel"
})}
name={"valueRequired" as keyof AttributePageFormData}
onChange={onChange}
@ -94,5 +124,6 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
</CardContent>
</Card>
);
};
AttributeDetails.displayName = "AttributeDetails";
export default AttributeDetails;

View file

@ -6,12 +6,12 @@ import TableFooter from "@material-ui/core/TableFooter";
import TableRow from "@material-ui/core/TableRow";
import makeStyles from "@material-ui/styles/makeStyles";
import React from "react";
import { FormattedMessage } from "react-intl";
import Checkbox from "@saleor/components/Checkbox";
import Skeleton from "@saleor/components/Skeleton";
import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination";
import i18n from "@saleor/i18n";
import { renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types";
import { translateBoolean } from "@saleor/utils/i18n";
@ -83,23 +83,39 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
toolbar={toolbar}
>
<TableCell className={classes.colSlug}>
{i18n.t("Attribute Code", { context: "attribute slug" })}
<FormattedMessage
defaultMessage="Attribute Code"
description="attribute list: slug column header"
id="attributeListSlugColumnHeader"
/>
</TableCell>
<TableCell className={classes.colName}>
{i18n.t("Default Label", { context: "attribute name" })}
<FormattedMessage
defaultMessage="Default Label"
description="attribute list: name column header"
id="attributeListNameColumnHeader"
/>
</TableCell>
<TableCell className={classes.colVisible}>
{i18n.t("Visible", { context: "attribute visibility" })}
<FormattedMessage
defaultMessage="Visible"
description="attribute list: visibility column header"
id="attributeListVisibilityColumnHeader"
/>
</TableCell>
<TableCell className={classes.colSearchable}>
{i18n.t("Searchable", {
context: "attribute can be searched in dashboard"
})}
<FormattedMessage
defaultMessage="Searchable"
description="attribute list: attribute can be searched in dashboard column header"
id="attributeListSearchableColumnHeader"
/>
</TableCell>
<TableCell className={classes.colFaceted}>
{i18n.t("Use in faceted search", {
context: "attribute can be searched in storefront"
})}
<FormattedMessage
defaultMessage="Use in faceted search"
description="attribute list: attribute can be searched in storefront column header"
id="attributeListFacetedColumnHeader"
/>
</TableCell>
</TableHead>
<TableFooter>
@ -170,7 +186,11 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
() => (
<TableRow>
<TableCell colSpan={numberOfColumns}>
{i18n.t("No attributes found")}
<FormattedMessage
defaultMessage="No attributes found"
description="no attributes found with present filters"
id="AttributeListNoAttributes"
/>
</TableCell>
</TableRow>
)

View file

@ -2,10 +2,11 @@ import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import AddIcon from "@material-ui/icons/Add";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { sectionNames } from "@saleor/intl";
import Container from "../../../components/Container";
import PageHeader from "../../../components/PageHeader";
import i18n from "../../../i18n";
import { ListActions, PageListProps } from "../../../types";
import { AttributeList_attributes_edges_node } from "../../types/AttributeList";
import AttributeList from "../AttributeList/AttributeList";
@ -17,11 +18,21 @@ export interface AttributeListPageProps extends PageListProps, ListActions {
const AttributeListPage: React.FC<AttributeListPageProps> = ({
onAdd,
...listProps
}) => (
}) => {
const intl = useIntl();
return (
<Container>
<PageHeader title={i18n.t("Attributes")}>
<PageHeader
title={intl.formatMessage(sectionNames.attributes)}
>
<Button onClick={onAdd} color="primary" variant="contained">
{i18n.t("Add attribute")} <AddIcon />
<FormattedMessage
defaultMessage="New attribute"
description="button"
id="attributeListPageNewAttribute"
/>
<AddIcon />
</Button>
</PageHeader>
<Card>
@ -29,5 +40,6 @@ const AttributeListPage: React.FC<AttributeListPageProps> = ({
</Card>
</Container>
);
};
AttributeListPage.displayName = "AttributeListPage";
export default AttributeListPage;

View file

@ -1,4 +1,5 @@
import React from "react";
import { useIntl } from "react-intl";
import slugify from "slugify";
import AppHeader from "@saleor/components/AppHeader";
@ -9,7 +10,7 @@ import Form from "@saleor/components/Form";
import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar";
import i18n from "@saleor/i18n";
import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc";
import { ReorderAction, UserError } from "@saleor/types";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
@ -62,6 +63,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
onValueReorder,
onValueUpdate
}) => {
const intl = useIntl();
const initialForm: AttributePageFormData =
attribute === null
? {
@ -109,12 +111,16 @@ const AttributePage: React.FC<AttributePageProps> = ({
<Form errors={errors} initial={initialForm} onSubmit={handleSubmit}>
{({ change, errors: formErrors, data, submit }) => (
<Container>
<AppHeader onBack={onBack}>{i18n.t("Attributes")}</AppHeader>
<AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.attributes)}
</AppHeader>
<PageHeader
title={
attribute === null
? i18n.t("Create New Attribute", {
context: "page title"
? intl.formatMessage({
defaultMessage: "Create New Attribute",
description: "page title",
id: "attributePageTitle"
})
: maybe(() => attribute.name)
}

View file

@ -3,13 +3,14 @@ import CardContent from "@material-ui/core/CardContent";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import CardSpacer from "@saleor/components/CardSpacer";
import CardTitle from "@saleor/components/CardTitle";
import ControlledSwitch from "@saleor/components/ControlledSwitch";
import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr";
import i18n from "@saleor/i18n";
import { commonMessages } from "@saleor/intl";
import { FormErrors } from "@saleor/types";
import { AttributePageFormData } from "../AttributePage";
@ -25,12 +26,19 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
errors,
disabled,
onChange
}) => (
}) => {
const intl = useIntl();
return (
<Card>
<CardTitle title={i18n.t("Properties")} />
<CardTitle title={intl.formatMessage(commonMessages.properties)} />
<CardContent>
{/* <Typography variant="subtitle1">
{i18n.t("General Properties")}
<FormattedMessage
defaultMessage="General Properties"
description="attribute general properties section"
id="attributePropertiesGeneralSectionTitle"
/>
</Typography>
<Hr />
<CardSpacer />
@ -40,11 +48,16 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
disabled={disabled}
label={
<>
<span>{i18n.t("Variant Attribute")}</span>
<FormattedMessage
defaultMessage="Variant Attribute"
description="attribute is variant-only"
id="attributePropertiesVariantOnly"
/>
<Typography variant="caption">
{i18n.t(
"If enabled, you'll be able to use this attribute to create product variants"
)}
<FormattedMessage
defaultMessage="If enabled, you'll be able to use this attribute to create product variants"
id="attributePropertiesVariantOnlyHelperText"
/>
</Typography>
</>
}
@ -52,14 +65,22 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
/> */}
<Typography variant="subtitle1">
{i18n.t("Storefront Properties")}
<FormattedMessage
defaultMessage="Storefront Properties"
description="attribute properties regarding storefront"
id="attributePropertiesStorefront"
/>
</Typography>
<Hr />
<ControlledSwitch
name={"filterableInStorefront" as keyof AttributePageFormData}
checked={data.filterableInStorefront}
disabled={disabled}
label={i18n.t("Use in faceted navigation")}
label={intl.formatMessage({
defaultMessage: "Use in faceted navigation",
description: "attribute is filterable in storefront",
id: "attributePropertiesUseInFacetedNavigation"
})}
onChange={onChange}
/>
{data.filterableInStorefront && (
@ -69,7 +90,11 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
fullWidth
helperText={errors.storefrontSearchPosition}
name={"storefrontSearchPosition" as keyof AttributePageFormData}
label={i18n.t("Position in faceted navigation")}
label={intl.formatMessage({
defaultMessage: "Position in faceted navigation",
description: "attribute position in storefront filters",
id: "attributePropertiesFacetedNavigationPosition"
})}
value={data.storefrontSearchPosition}
onChange={onChange}
/>
@ -79,15 +104,20 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
name={"visibleInStorefront" as keyof AttributePageFormData}
checked={data.visibleInStorefront}
disabled={disabled}
label={i18n.t("Visible on Product Page in Storefront", {
context: "attribute"
label={intl.formatMessage({
defaultMessage: "Visible on Product Page in Storefront",
description: "attribute",
id: "attributePropertiesVisibility"
})}
onChange={onChange}
/>
<CardSpacer />
<Typography variant="subtitle1">
{i18n.t("Dashboard Properties")}
<FormattedMessage
defaultMessage="Dashboard Properties"
description="attribute properties regarding dashboard"
id="attributePropertiesDashboard"
/>
</Typography>
<Hr />
<CardSpacer />
@ -95,12 +125,14 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
name={"filterableInDashboard" as keyof AttributePageFormData}
checked={data.filterableInDashboard}
disabled={disabled}
label={i18n.t("Use in Filtering")}
label={intl.formatMessage({
defaultMessage: "Use in Filtering",
description: "use attribute in filtering",
id: "attributePropertiesDashboardFiltering"
})}
secondLabel={
<Typography variant="caption">
{i18n.t(
"If enabled, youll be able to use this attribute to filter products in product list."
)}
<FormattedMessage defaultMessage="If enabled, youll be able to use this attribute to filter products in product list." />
</Typography>
}
onChange={onChange}
@ -110,12 +142,13 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
name={"availableInGrid" as keyof AttributePageFormData}
checked={data.availableInGrid}
disabled={disabled}
label={i18n.t("Add to Column Options")}
label={intl.formatMessage({
defaultMessage: "Add to Column Options",
description: "add attribute as column in product list table"
})}
secondLabel={
<Typography variant="caption">
{i18n.t(
"If enable this attribute can be used as a column in product table."
)}
<FormattedMessage defaultMessage="If enable this attribute can be used as a column in product table." />
</Typography>
}
onChange={onChange}
@ -123,5 +156,6 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
</CardContent>
</Card>
);
};
AttributeProperties.displayName = "AttributeProperties";
export default AttributeProperties;

View file

@ -1,9 +1,9 @@
import DialogContentText from "@material-ui/core/DialogContentText";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import i18n from "@saleor/i18n";
export interface AttributeValueDeleteDialogProps {
attributeName: string;
@ -23,30 +23,46 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
onClose,
onConfirm,
open
}) => (
}) => {
const intl = useIntl();
return (
<ActionDialog
open={open}
onClose={onClose}
confirmButtonState={confirmButtonState}
onConfirm={onConfirm}
variant="delete"
title={i18n.t("Remove attribute value")}
title={intl.formatMessage({
defaultMessage: "Remove attribute value",
description: "dialog title",
id: "attributeValueDeleteDialogTitle"
})}
>
<DialogContentText>
{useName
? i18n.t(
'Are you sure you want to remove "{{ name }}" value? If you remove it you wont be able to assign it to any of the products with "{{ attributeName }}" attribute.',
{
{useName ? (
<FormattedMessage
defaultMessage='Are you sure you want to remove "{ name }" value? If you remove it you wont be able to assign it to any of the products with "{ attributeName }" attribute.'
id="attributeValueDeleteDialogContentWithAttributeName"
values={{
attributeName,
name
}
)
: i18n.t('Are you sure you want to remove "{{ name }}" value?', {
}}
/>
) : (
<FormattedMessage
defaultMessage='Are you sure you want to remove "{ name }" value?'
description="remove attribute value"
id="attributeValueDeleteDialogContentWithoutAttributeName"
values={{
name
})}
}}
/>
)}
</DialogContentText>
</ActionDialog>
);
};
AttributeValueDeleteDialog.displayName = "AttributeValueDeleteDialog";
export default AttributeValueDeleteDialog;

View file

@ -5,13 +5,14 @@ import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import TextField from "@material-ui/core/TextField";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ConfirmButton, {
ConfirmButtonTransitionState
} from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import i18n from "@saleor/i18n";
import { commonMessages } from "@saleor/intl";
import { maybe } from "@saleor/misc";
import { UserError } from "@saleor/types";
import { AttributeDetails_attribute_values } from "../../types/AttributeDetails";
@ -40,6 +41,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
onSubmit,
open
}) => {
const intl = useIntl();
const initialForm: AttributeValueEditDialogFormData = {
name: maybe(() => attributeValue.name, "")
};
@ -48,13 +50,19 @@ const AttributeValueEditDialog: React.StatelessComponent<
return (
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
<DialogTitle>
{attributeValue === null
? i18n.t("Add Value", {
context: "add attribute value"
})
: i18n.t("Edit Value", {
context: "edit attribute value"
})}
{attributeValue === null ? (
<FormattedMessage
defaultMessage="Add Value"
description="add attribute value"
id="attributeValueEditDialogTitleNewValue"
/>
) : (
<FormattedMessage
defaultMessage="Edit Value"
description="edit attribute value"
id="attributeValueEditDialogTitle"
/>
)}
</DialogTitle>
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
{({ change, data, errors: formErrors, submit }) => (
@ -67,8 +75,10 @@ const AttributeValueEditDialog: React.StatelessComponent<
fullWidth
helperText={formErrors.name}
name={"name" as keyof AttributeValueEditDialogFormData}
label={i18n.t("Name", {
context: "attribute name"
label={intl.formatMessage({
defaultMessage: "Name",
description: "attribute name",
id: "attributeValueEditDialogNameField"
})}
value={data.name}
onChange={change}
@ -76,7 +86,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
{i18n.t("Cancel", { context: "button" })}
<FormattedMessage {...commonMessages.cancel} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
@ -84,7 +94,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
variant="contained"
onClick={submit}
>
{i18n.t("Save")}
<FormattedMessage {...commonMessages.save} />
</ConfirmButton>
</DialogActions>
</>

View file

@ -9,6 +9,7 @@ import TableRow from "@material-ui/core/TableRow";
import DeleteIcon from "@material-ui/icons/Delete";
import makeStyles from "@material-ui/styles/makeStyles";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import CardTitle from "@saleor/components/CardTitle";
import Skeleton from "@saleor/components/Skeleton";
@ -16,7 +17,6 @@ import {
SortableTableBody,
SortableTableRow
} from "@saleor/components/SortableTable";
import i18n from "@saleor/i18n";
import { maybe, renderCollection, stopPropagation } from "@saleor/misc";
import { ReorderAction } from "@saleor/types";
import { AttributeDetailsFragment_values } from "../../types/AttributeDetailsFragment";
@ -63,14 +63,23 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
values
}) => {
const classes = useStyles({});
const intl = useIntl();
return (
<Card>
<CardTitle
title={i18n.t("Attribute Values")}
title={intl.formatMessage({
defaultMessage: "Attribute Values",
description: "section header",
id: "attributeValuesHeader"
})}
toolbar={
<Button color="primary" variant="text" onClick={onValueAdd}>
{i18n.t("Add value", { context: "button" })}
<FormattedMessage
defaultMessage="Add value"
description="add attribute value button"
id="attributeValuesAddButton"
/>
</Button>
}
/>
@ -79,10 +88,18 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
<TableRow>
<TableCell className={classes.columnDrag} />
<TableCell className={classes.columnAdmin}>
{i18n.t("Admin")}
<FormattedMessage
defaultMessage="Admin"
description="attribute values list: slug column header"
id="attributeValuesSlugColumnHeader"
/>
</TableCell>
<TableCell className={classes.columnStore}>
{i18n.t("Default Store View")}
<FormattedMessage
defaultMessage="Default Store View"
description="attribute values list: name column header"
id="attributeValuesNameColumnHeader"
/>
</TableCell>
<TableCell />
</TableRow>
@ -116,7 +133,13 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
),
() => (
<TableRow>
<TableCell colSpan={2}>{i18n.t("No values found")}</TableCell>
<TableCell colSpan={2}>
<FormattedMessage
defaultMessage="No values found"
description="No attribute values found"
id="attributeValuesNotFound"
/>
</TableCell>
</TableRow>
)
)}

View file

@ -2,8 +2,9 @@ import { parse as parseQs } from "qs";
import React from "react";
import { Route, RouteComponentProps, Switch } from "react-router-dom";
import { sectionNames } from "@saleor/intl";
import { useIntl } from "react-intl";
import { WindowTitle } from "../components/WindowTitle";
import i18n from "../i18n";
import {
attributeAddPath,
AttributeAddUrlQueryParams,
@ -42,9 +43,12 @@ const AttributeDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
);
};
export const AttributeSection: React.FC = () => (
export const AttributeSection: React.FC = () => {
const intl = useIntl();
return (
<>
<WindowTitle title={i18n.t("Attributes")} />
<WindowTitle title={intl.formatMessage(sectionNames.attributes)} />
<Switch>
<Route exact path={attributeListPath} component={AttributeList} />
<Route exact path={attributeAddPath} component={AttributeCreate} />
@ -52,4 +56,5 @@ export const AttributeSection: React.FC = () => (
</Switch>
</>
);
};
export default AttributeSection;

View file

@ -1,9 +1,9 @@
import React from "react";
import { useIntl } from "react-intl";
import slugify from "slugify";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import i18n from "@saleor/i18n";
import { getMutationState, maybe } from "@saleor/misc";
import { ReorderEvent, UserError } from "@saleor/types";
import {
@ -42,6 +42,7 @@ function areValuesEqual(
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
const navigate = useNavigator();
const notify = useNotifier();
const intl = useIntl();
const [values, setValues] = React.useState<
AttributeValueEditDialogFormData[]
@ -75,7 +76,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
};
const handleCreate = (data: AttributeCreate) => {
if (data.attributeCreate.errors.length === 0) {
notify({ text: i18n.t("Successfully created attribute") });
notify({
text: intl.formatMessage({
defaultMessage: "Successfully created attribute",
id: "attributeCreateAttributeCreateSuccess"
})
});
navigate(attributeUrl(data.attributeCreate.attribute.id));
}
};
@ -84,10 +90,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
setValueErrors([
{
field: "name",
message: i18n.t("A value named {{ name }} already exists", {
context: "value edit error",
message: intl.formatMessage(
{
defaultMessage: "A value named { name } already exists",
description: "attribute value edit error",
id: "attributeCreateErrorExists"
},
{
name: input.name
})
}
)
}
]);
} else {
@ -100,10 +112,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
setValueErrors([
{
field: "name",
message: i18n.t("A value named {{ name }} already exists", {
context: "value edit error",
message: intl.formatMessage(
{
defaultMessage: "A value named { name } already exists",
description: "attribute value edit error",
id: "attributeCreateErrorExists"
},
{
name: input.name
})
}
)
}
]);
} else {

View file

@ -1,8 +1,9 @@
import React from "react";
import { useIntl } from "react-intl";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import i18n from "@saleor/i18n";
import { commonMessages } from "@saleor/intl";
import { getMutationState, maybe } from "@saleor/misc";
import { ReorderEvent } from "@saleor/types";
import { move } from "@saleor/utils/lists";
@ -40,6 +41,7 @@ interface AttributeDetailsProps {
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
const navigate = useNavigator();
const notify = useNotifier();
const intl = useIntl();
const closeModal = () =>
navigate(
@ -63,39 +65,54 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
const handleDelete = (data: AttributeDelete) => {
if (data.attributeDelete.errors.length === 0) {
notify({ text: i18n.t("Attribute removed") });
notify({
text: intl.formatMessage({
defaultMessage: "Attribute removed",
id: "attributeDetailsAttributeRemoveSuccess"
})
});
navigate(attributeListUrl());
}
};
const handleValueDelete = (data: AttributeValueDelete) => {
if (data.attributeValueDelete.errors.length === 0) {
notify({ text: i18n.t("Value removed") });
notify({
text: intl.formatMessage({
defaultMessage: "Value removed",
description: "attribute value removed",
id: "attributeDetailsAttributeValueRemoveSuccess"
})
});
closeModal();
}
};
const handleUpdate = (data: AttributeUpdate) => {
if (data.attributeUpdate.errors.length === 0) {
notify({ text: i18n.t("Saved changes") });
notify({ text: intl.formatMessage(commonMessages.savedChanges) });
}
};
const handleValueUpdate = (data: AttributeValueUpdate) => {
if (data.attributeValueUpdate.errors.length === 0) {
notify({ text: i18n.t("Saved changes") });
notify({ text: intl.formatMessage(commonMessages.savedChanges) });
closeModal();
}
};
const handleValueCreate = (data: AttributeValueCreate) => {
if (data.attributeValueCreate.errors.length === 0) {
notify({ text: i18n.t("Added new value") });
notify({
text: intl.formatMessage({
defaultMessage: "Added new value",
description: "added new attribute value",
id: "attributeDetailsAttributeValueCreateSuccess"
})
});
closeModal();
}
};
const handleValueReorderMutation = (data: AttributeValueReorder) => {
if (data.attributeReorderValues.errors.length !== 0) {
notify({
text: i18n.t("Error: {{ errorMessage }}", {
errorMessage: data.attributeReorderValues.errors[0].message
})
text: data.attributeReorderValues.errors[0].message
});
}
};

View file

@ -1,6 +1,7 @@
import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete";
import React from "react";
import { useIntl } from "react-intl";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
@ -9,7 +10,6 @@ import usePaginator, {
} from "@saleor/hooks/usePaginator";
import { PAGINATE_BY } from "../../../config";
import useBulkActions from "../../../hooks/useBulkActions";
import i18n from "../../../i18n";
import { getMutationState, maybe } from "../../../misc";
import AttributeBulkDeleteDialog from "../../components/AttributeBulkDeleteDialog";
import AttributeListPage from "../../components/AttributeListPage";
@ -35,6 +35,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
params.ids
);
const intl = useIntl();
const closeModal = () =>
navigate(
@ -71,7 +72,11 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
if (data.attributeBulkDelete.errors.length === 0) {
closeModal();
notify({
text: i18n.t("Attributes removed")
text: intl.formatMessage({
defaultMessage: "Attributes successfully removed",
description: "remove multiple attributes",
id: "attributeListAttributesRemoved"
})
});
reset();
refetch();
@ -116,12 +121,15 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
/>
<AttributeBulkDeleteDialog
confirmButtonState={bulkDeleteMutationState}
open={params.action === "remove"}
open={
params.action === "remove" &&
maybe(() => params.ids.length > 0)
}
onConfirm={() =>
attributeBulkDelete({ variables: { ids: params.ids } })
}
onClose={closeModal}
quantity={maybe(() => params.ids.length.toString(), "...")}
quantity={maybe(() => params.ids.length)}
/>
</>
);