diff --git a/.gitignore b/.gitignore index 04c8c53e7..14f66e4e6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,8 @@ !.tx *.css *.log -*.pot *.pyc +*.mo local_settings.py __pycache__/ build/ diff --git a/CHANGELOG.md b/CHANGELOG.md index dbca8006b..0f5bf9dbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,4 @@ All notable, unreleased changes to this project will be documented in this file. - Fix configure menu section - #109 by @benekex2 - Add switch to make attribute available in product list as a column - #99 by @dominik-zeglen - Add tc tags for E2E testing - #134 by @dominik-zeglen +- Use react-intl - #105 by @dominik-zeglen diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..723c15517 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,48 @@ +module.exports = api => { + const isTest = api.env("test"); + const isStorybook = api.env("storybook"); + + const ignore = + isTest || isStorybook + ? [] + : ["**/*.test.ts", "**/*.test.tsx", "src/storybook"]; + + const presets = [ + [ + "@babel/preset-env", + { + corejs: "3.2.1", + modules: isTest ? "auto" : false, + useBuiltIns: "usage" + } + ], + "@babel/preset-react", + "@babel/preset-typescript" + ]; + + const plugins = [ + "@babel/plugin-proposal-numeric-separator", + "@babel/plugin-proposal-class-properties", + [ + "@babel/plugin-proposal-decorators", + { + decoratorsBeforeExport: true + } + ], + "@babel/plugin-proposal-object-rest-spread", + "react-intl-auto", + [ + "react-intl", + { + extractFromFormatMessageCall: true, + messagesDir: "build/locale/" + } + ] + ]; + + return { + presets, + plugins, + ignore + }; +}; diff --git a/locale/messages.pot b/locale/messages.pot new file mode 100644 index 000000000..2e1462a25 --- /dev/null +++ b/locale/messages.pot @@ -0,0 +1,8316 @@ +msgid "" +msgstr "" +"POT-Creation-Date: 2019-08-29T12:47:44.847Z\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"MIME-Version: 1.0\n" +"X-Generator: react-intl-po\n" + + +#: build/locale/src/categories/components/CategoryBackground/CategoryBackground.json +#. [src.categories.components.CategoryBackground.3289097895] - field is optional +#. defaultMessage is: +#. (Optional) +#: build/locale/src/collections/components/CollectionImage/CollectionImage.json +#. [src.collections.components.CollectionImage.3289097895] - field is optional +#. defaultMessage is: +#. (Optional) +msgctxt "field is optional" +msgid "(Optional)" +msgstr "" + +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.2805838453] - field is optional +#. defaultMessage is: +#. *Optional. Adding product to collection helps users find it. +msgctxt "field is optional" +msgid "*Optional. Adding product to collection helps users find it." +msgstr "" + +#: build/locale/src/attributes/views/AttributeCreate/AttributeCreate.json +#. [src.attributes.views.AttributeCreate.2348058468] - attribute value edit error +#. defaultMessage is: +#. A value named {name} already exists +msgctxt "attribute value edit error" +msgid "A value named {name} already exists" +msgstr "" + +#: build/locale/src/misc.json +#. [src.accommodation] - tax rate +#. defaultMessage is: +#. Accommodation +msgctxt "tax rate" +msgid "Accommodation" +msgstr "" + +#: build/locale/src/staff/components/StaffStatus/StaffStatus.json +#. [src.staff.components.StaffStatus.2183517419] - section header +#. defaultMessage is: +#. Account Status +msgctxt "section header" +msgid "Account Status" +msgstr "" + +#: build/locale/src/staff/components/StaffList/StaffList.json +#. [src.staff.components.StaffList.3247064221] - staff member status +#. defaultMessage is: +#. Active +msgctxt "staff member status" +msgid "Active" +msgstr "" + +#: build/locale/src/discounts/components/VoucherDates/VoucherDates.json +#. [src.discounts.components.VoucherDates.1662220323] - time during voucher is active, header +#. defaultMessage is: +#. Active Dates +msgctxt "time during voucher is active, header" +msgid "Active Dates" +msgstr "" + +#: build/locale/src/home/components/HomeActivityCard/HomeActivityCard.json +#. [homeActivityCardHeader] - header +#. defaultMessage is: +#. Activity +msgctxt "header" +msgid "Activity" +msgstr "" + +#: build/locale/src/components/ListField/ListField.json +#. [src.components.ListField.3099331554] - button +#. defaultMessage is: +#. Add +msgctxt "button" +msgid "Add" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.json +#. [src.customers.components.CustomerAddressDialog.3769321414] - dialog title +#. defaultMessage is: +#. Add Address +msgctxt "dialog title" +msgid "Add Address" +msgstr "" + +#: build/locale/src/components/Filter/Filter.json +#. [src.components.Filter.2852521946] - button +#. defaultMessage is: +#. Add Filter +msgctxt "button" +msgid "Add Filter" +msgstr "" + +#: build/locale/src/components/RichTextEditor/ImageSource.json +#. [src.components.RichTextEditor.1603794322] - dialog header +#. defaultMessage is: +#. Add Image Link +msgctxt "dialog header" +msgid "Add Image Link" +msgstr "" + +#: build/locale/src/navigation/components/MenuItemDialog/MenuItemDialog.json +#. [menuItemDialogAddItem] - create new menu item, header +#. defaultMessage is: +#. Add Item +msgctxt "create new menu item, header" +msgid "Add Item" +msgstr "" + +#: build/locale/src/navigation/components/MenuCreateDialog/MenuCreateDialog.json +#. [menuCreateDialogHeader] - dialog header +#. defaultMessage is: +#. Add Menu +msgctxt "dialog header" +msgid "Add Menu" +msgstr "" + +#: build/locale/src/navigation/components/MenuListPage/MenuListPage.json +#. [menuListPageAddMenu] - button +#. defaultMessage is: +#. Add Menu +msgctxt "button" +msgid "Add Menu" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.json +#. [src.siteSettings.components.SiteSettingsKeyDialog.1238948746] - dialog header +#. defaultMessage is: +#. Add New Authorization Key +msgctxt "dialog header" +msgid "Add New Authorization Key" +msgstr "" + +#: build/locale/src/pages/components/PageDetailsPage/PageDetailsPage.json +#. [src.pages.components.PageDetailsPage.755314116] - page header +#. defaultMessage is: +#. Add Page +msgctxt "page header" +msgid "Add Page" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.2892088870] - dialog header +#. defaultMessage is: +#. Add Price Rate +msgctxt "dialog header" +msgid "Add Price Rate" +msgstr "" + +#: build/locale/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.json +#. [src.orders.components.OrderProductAddDialog.2775402904] - dialog header +#. defaultMessage is: +#. Add Product +msgctxt "dialog header" +msgid "Add Product" +msgstr "" + +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.2775402904] - button +#. defaultMessage is: +#. Add Product +msgctxt "button" +msgid "Add Product" +msgstr "" + +#: build/locale/src/discounts/components/SaleListPage/SaleListPage.json +#. [src.discounts.components.SaleListPage.1742771332] - button +#. defaultMessage is: +#. Add Sale +msgctxt "button" +msgid "Add Sale" +msgstr "" + +#: build/locale/src/staff/components/StaffAddMemberDialog/StaffAddMemberDialog.json +#. [src.staff.components.StaffAddMemberDialog.3490059488] - dialog header +#. defaultMessage is: +#. Add Staff Member +msgctxt "dialog header" +msgid "Add Staff Member" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.json +#. [src.attributes.components.AttributeValueEditDialog.1841790893] - add attribute value +#. defaultMessage is: +#. Add Value +msgctxt "add attribute value" +msgid "Add Value" +msgstr "" + +#: build/locale/src/products/views/ProductVariantCreate.json +#. [src.products.views.2178905289] - header +#. defaultMessage is: +#. Add Variant +msgctxt "header" +msgid "Add Variant" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1397795758] - add weight based shipping method, dialog header +#. defaultMessage is: +#. Add Weight Rate +msgctxt "add weight based shipping method, dialog header" +msgid "Add Weight Rate" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.json +#. [src.customers.components.CustomerAddressListPage.3623935073] - button +#. defaultMessage is: +#. Add address +msgctxt "button" +msgid "Add address" +msgstr "" + +#: build/locale/src/attributes/components/AttributeListPage/AttributeListPage.json +#. [src.attributes.components.AttributeListPage.350498821] - button +#. defaultMessage is: +#. Add attribute +msgctxt "button" +msgid "Add attribute" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.json +#. [src.siteSettings.components.SiteSettingsKeyDialog.50561933] - button +#. defaultMessage is: +#. Add authentication +msgctxt "button" +msgid "Add authentication" +msgstr "" + +#: build/locale/src/categories/components/CategoryListPage/CategoryListPage.json +#. [src.categories.components.CategoryListPage.228151782] - button +#. defaultMessage is: +#. Add category +msgctxt "button" +msgid "Add category" +msgstr "" + +#: build/locale/src/collections/components/CollectionCreatePage/CollectionCreatePage.json +#. [src.collections.components.CollectionCreatePage.3958681866] - page header +#. defaultMessage is: +#. Add collection +msgctxt "page header" +msgid "Add collection" +msgstr "" + +#: build/locale/src/collections/components/CollectionListPage/CollectionListPage.json +#. [src.collections.components.CollectionListPage.3958681866] - button +#. defaultMessage is: +#. Add collection +msgctxt "button" +msgid "Add collection" +msgstr "" + +#: build/locale/src/customers/components/CustomerCreatePage/CustomerCreatePage.json +#. [src.customers.components.CustomerCreatePage.1934221653] - page header +#. defaultMessage is: +#. Add customer +msgctxt "page header" +msgid "Add customer" +msgstr "" + +#: build/locale/src/customers/components/CustomerListPage/CustomerListPage.json +#. [src.customers.components.CustomerListPage.1934221653] - button +#. defaultMessage is: +#. Add customer +msgctxt "button" +msgid "Add customer" +msgstr "" + +#: build/locale/src/components/Filter/FilterContent.json +#. [src.components.Filter.2851720415] - button +#. defaultMessage is: +#. Add filter +msgctxt "button" +msgid "Add filter" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.json +#. [src.siteSettings.components.SiteSettingsKeys.1114030884] - button +#. defaultMessage is: +#. Add key +msgctxt "button" +msgid "Add key" +msgstr "" + +#: build/locale/src/navigation/components/MenuItems/MenuItems.json +#. [menuItemsAddItem] - add new menu item +#. defaultMessage is: +#. Add new item +msgctxt "add new menu item" +msgid "Add new item" +msgstr "" + +#: build/locale/src/navigation/components/MenuItems/MenuItems.json +#. [menuItemsPlaceholder] +#. defaultMessage is: +#. Add new menu item to begin creating menu +msgctxt "description" +msgid "Add new menu item to begin creating menu" +msgstr "" + +#: build/locale/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.json +#. [src.components.MultiAutocompleteSelectField.1477537381] - add custom option to select input +#. defaultMessage is: +#. Add new value: {value} +msgctxt "add custom option to select input" +msgid "Add new value: {value}" +msgstr "" + +#: build/locale/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.json +#. [src.components.SingleAutocompleteSelectField.1477537381] - add custom select input option +#. defaultMessage is: +#. Add new value: {value} +msgctxt "add custom select input option" +msgid "Add new value: {value}" +msgstr "" + +#: build/locale/src/components/RichTextEditor/LinkSource.json +#. [src.components.RichTextEditor.2160163587] - button +#. defaultMessage is: +#. Add or Edit Link +msgctxt "button" +msgid "Add or Edit Link" +msgstr "" + +#: build/locale/src/pages/components/PageListPage/PageListPage.json +#. [src.pages.components.PageListPage.1767905232] - button +#. defaultMessage is: +#. Add page +msgctxt "button" +msgid "Add page" +msgstr "" + +#: build/locale/src/categories/components/CategoryProducts/CategoryProducts.json +#. [src.categories.components.CategoryProducts.3554578821] - button +#. defaultMessage is: +#. Add product +#: build/locale/src/categories/components/CategoryProductsCard/CategoryProductsCard.json +#. [src.categories.components.CategoryProductsCard.3554578821] - button +#. defaultMessage is: +#. Add product +msgctxt "button" +msgid "Add product" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.json +#. [src.productTypes.components.ProductTypeListPage.889729490] - button +#. defaultMessage is: +#. Add product type +msgctxt "button" +msgid "Add product type" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetails/OrderDraftDetails.json +#. [src.orders.components.OrderDraftDetails.2528459381] - button +#. defaultMessage is: +#. Add products +msgctxt "button" +msgid "Add products" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.352297149] - button +#. defaultMessage is: +#. Add rate +msgctxt "button" +msgid "Add rate" +msgstr "" + +#: build/locale/src/categories/components/CategoryCreatePage/CategoryCreatePage.json +#. [src.categories.components.CategoryCreatePage.2563994280] +#. defaultMessage is: +#. Add search engine title and description to make this category easier to find +#: build/locale/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.json +#. [src.categories.components.CategoryUpdatePage.2563994280] +#. defaultMessage is: +#. Add search engine title and description to make this category easier to find +msgctxt "description" +msgid "Add search engine title and description to make this category easier to find" +msgstr "" + +#: build/locale/src/collections/components/CollectionCreatePage/CollectionCreatePage.json +#. [src.collections.components.CollectionCreatePage.946315389] +#. defaultMessage is: +#. Add search engine title and description to make this collection easier to find +#: build/locale/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.json +#. [src.collections.components.CollectionDetailsPage.946315389] +#. defaultMessage is: +#. Add search engine title and description to make this collection easier to find +msgctxt "description" +msgid "Add search engine title and description to make this collection easier to find" +msgstr "" + +#: build/locale/src/pages/components/PageDetailsPage/PageDetailsPage.json +#. [src.pages.components.PageDetailsPage.1996767833] +#. defaultMessage is: +#. Add search engine title and description to make this page easier to find +msgctxt "description" +msgid "Add search engine title and description to make this page easier to find" +msgstr "" + +#: build/locale/src/products/components/ProductCreatePage/ProductCreatePage.json +#. [src.products.components.ProductCreatePage.2706108815] +#. defaultMessage is: +#. Add search engine title and description to make this product easier to find +#: build/locale/src/products/components/ProductUpdatePage/ProductUpdatePage.json +#. [src.products.components.ProductUpdatePage.2706108815] +#. defaultMessage is: +#. Add search engine title and description to make this product easier to find +msgctxt "description" +msgid "Add search engine title and description to make this product easier to find" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.json +#. [src.orders.components.OrderDraftDetailsSummary.2429341469] - button +#. defaultMessage is: +#. Add shipping carrier +msgctxt "button" +msgid "Add shipping carrier" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZonesList/ShippingZonesList.json +#. [src.shipping.components.ShippingZonesList.2474410767] - button +#. defaultMessage is: +#. Add shipping zone +msgctxt "button" +msgid "Add shipping zone" +msgstr "" + +#: build/locale/src/staff/components/StaffListPage/StaffListPage.json +#. [src.staff.components.StaffListPage.802625341] - button +#. defaultMessage is: +#. Add staff member +msgctxt "button" +msgid "Add staff member" +msgstr "" + +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.435697837] - button +#. defaultMessage is: +#. Add subcategory +msgctxt "button" +msgid "Add subcategory" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.673770329] - add attribute as column in product list table +#. defaultMessage is: +#. Add to Column Options +msgctxt "add attribute as column in product list table" +msgid "Add to Column Options" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.1119771899] - fulfillment group tracking number +#. defaultMessage is: +#. Add tracking +msgctxt "fulfillment group tracking number" +msgid "Add tracking" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentTrackingDialog/OrderFulfillmentTrackingDialog.json +#. [src.orders.components.OrderFulfillmentTrackingDialog.3680864271] - dialog header +#. defaultMessage is: +#. Add tracking code +msgctxt "dialog header" +msgid "Add tracking code" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValues/AttributeValues.json +#. [src.attributes.components.AttributeValues.254756045] - add attribute value button +#. defaultMessage is: +#. Add value +msgctxt "add attribute value button" +msgid "Add value" +msgstr "" + +#: build/locale/src/products/components/ProductVariantNavigation/ProductVariantNavigation.json +#. [src.products.components.ProductVariantNavigation.2845381934] - button +#. defaultMessage is: +#. Add variant +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.2845381934] - button +#. defaultMessage is: +#. Add variant +msgctxt "button" +msgid "Add variant" +msgstr "" + +#: build/locale/src/discounts/components/VoucherListPage/VoucherListPage.json +#. [src.discounts.components.VoucherListPage.1536809153] - button +#. defaultMessage is: +#. Add voucher +msgctxt "button" +msgid "Add voucher" +msgstr "" + +#: build/locale/src/attributes/views/AttributeDetails/AttributeDetails.json +#. [src.attributes.views.AttributeDetails.634268988] - added new attribute value +#. defaultMessage is: +#. Added new value +msgctxt "added new attribute value" +msgid "Added new value" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.2001540731] +#. defaultMessage is: +#. Added product to collection +msgctxt "description" +msgid "Added product to collection" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddresses/CustomerAddresses.json +#. [src.customers.components.CustomerAddresses.359810770] - subsection header +#. defaultMessage is: +#. Address +msgctxt "subsection header" +msgid "Address" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddresses/CustomerAddresses.json +#. [src.customers.components.CustomerAddresses.1967111456] - header +#. defaultMessage is: +#. Address Information +msgctxt "header" +msgid "Address Information" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.1363074570] +#. defaultMessage is: +#. Address line 1 +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.1363074570] +#. defaultMessage is: +#. Address line 1 +msgctxt "description" +msgid "Address line 1" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.3121963259] +#. defaultMessage is: +#. Address line 2 +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.3121963259] +#. defaultMessage is: +#. Address line 2 +msgctxt "description" +msgid "Address line 2" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddress/CustomerAddress.json +#. [src.customers.components.CustomerAddress.1320082647] - addres card header +#. defaultMessage is: +#. Address {addressNumber} +msgctxt "addres card header" +msgid "Address {addressNumber}" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValues/AttributeValues.json +#. [src.attributes.components.AttributeValues.1565474525] - attribute values list: slug column header +#. defaultMessage is: +#. Admin +msgctxt "attribute values list: slug column header" +msgid "Admin" +msgstr "" + +#: build/locale/src/misc.json +#. [src.admissionToCulturalEvents] - tax rate +#. defaultMessage is: +#. Admission to cultural events +msgctxt "tax rate" +msgid "Admission to cultural events" +msgstr "" + +#: build/locale/src/misc.json +#. [src.admissionToEntertainmentEvents] - tax rate +#. defaultMessage is: +#. Admission to entertainment events +msgctxt "tax rate" +msgid "Admission to entertainment events" +msgstr "" + +#: build/locale/src/misc.json +#. [src.admissionToSportingEvents] - tax rate +#. defaultMessage is: +#. Admission to sporting events +msgctxt "tax rate" +msgid "Admission to sporting events" +msgstr "" + +#: build/locale/src/misc.json +#. [src.advertising] - tax rate +#. defaultMessage is: +#. Advertising +msgctxt "tax rate" +msgid "Advertising" +msgstr "" + +#: build/locale/src/misc.json +#. [src.agriculturalSupplies] - tax rate +#. defaultMessage is: +#. Agricultural supplies +msgctxt "tax rate" +msgid "Agricultural supplies" +msgstr "" + +#: build/locale/src/orders/components/OrderListPage/OrderListPage.json +#. [src.orders.components.OrderListPage.875489544] - tab name +#. defaultMessage is: +#. All Orders +msgctxt "tab name" +msgid "All Orders" +msgstr "" + +#: build/locale/src/products/components/ProductImageNavigation/ProductImageNavigation.json +#. [src.products.components.ProductImageNavigation.3060635772] - section header +#. defaultMessage is: +#. All Photos +msgctxt "section header" +msgid "All Photos" +msgstr "" + +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.821159718] - tab name +#. defaultMessage is: +#. All Products +msgctxt "tab name" +msgid "All Products" +msgstr "" + +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.3229914152] - section header +#. defaultMessage is: +#. All Subcategories +msgctxt "section header" +msgid "All Subcategories" +msgstr "" + +#: build/locale/src/taxes/components/TaxConfiguration/TaxConfiguration.json +#. [src.taxes.components.TaxConfiguration.142803418] +#. defaultMessage is: +#. All products prices are entered with tax included +msgctxt "description" +msgid "All products prices are entered with tax included" +msgstr "" + +#: build/locale/src/products/components/ProductStock/ProductStock.json +#. [src.products.components.ProductStock.1680952454] - allocated product stock +#. defaultMessage is: +#. Allocated: {quantity} +msgctxt "allocated product stock" +msgid "Allocated: {quantity}" +msgstr "" + +#: build/locale/src/products/components/ProductVariantStock/ProductVariantStock.json +#. [src.products.components.ProductVariantStock.1680952454] - variant allocated stock +#. defaultMessage is: +#. Allocated: {quantity} +msgctxt "variant allocated stock" +msgid "Allocated: {quantity}" +msgstr "" + +#: build/locale/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.json +#. [src.orders.components.OrderPaymentDialog.75546233] - amount of refunded money +#. defaultMessage is: +#. Amount +msgctxt "amount of refunded money" +msgid "Amount" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.4172383244] +#. defaultMessage is: +#. Anonymous user +msgctxt "description" +msgid "Anonymous user" +msgstr "" + +#: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json +#. [src.discounts.components.VoucherSummary.2735425668] - voucher +#. defaultMessage is: +#. Applies to +msgctxt "voucher" +msgid "Applies to" +msgstr "" + +#: build/locale/src/orders/components/OrderCancelDialog/OrderCancelDialog.json +#. [src.orders.components.OrderCancelDialog.3981375672] +#. defaultMessage is: +#. Are you sure you want to cancel order #{orderNumber}? +msgctxt "description" +msgid "Are you sure you want to cancel order #{orderNumber}?" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.json +#. [src.orders.components.OrderFulfillmentCancelDialog.2569854889] +#. defaultMessage is: +#. Are you sure you want to cancel this fulfillment? +msgctxt "description" +msgid "Are you sure you want to cancel this fulfillment?" +msgstr "" + +#: build/locale/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.json +#. [src.orders.components.OrderBulkCancelDialog.276130122] +#. defaultMessage is: +#. Are you sure you want to cancel {counter,plural,one{this order} other{{displayQuantity} orders}}? +msgctxt "description" +msgid "Are you sure you want to cancel {counter,plural,one{this order} other{{displayQuantity} orders}}?" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json +#. [src.attributes.components.AttributeValueDeleteDialog.273524270] - delete attribute value +#. defaultMessage is: +#. Are you sure you want to delete "{name}" value? +msgctxt "delete attribute value" +msgid "Are you sure you want to delete \"{name}\" value?" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json +#. [src.attributes.components.AttributeValueDeleteDialog.1934550550] +#. defaultMessage is: +#. Are you sure you want to delete "{name}" value? If you delete it you won’t be able to assign it to any of the products with "{attributeName}" attribute. +msgctxt "description" +msgid "Are you sure you want to delete \"{name}\" value? If you delete it you won’t be able to assign it to any of the products with \"{attributeName}\" attribute." +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.2402899582] +#. defaultMessage is: +#. Are you sure you want to delete collection's image? +msgctxt "description" +msgid "Are you sure you want to delete collection's image?" +msgstr "" + +#: build/locale/src/navigation/views/MenuDetails/index.json +#. [menuDetailsDeleteMenuContent] +#. defaultMessage is: +#. Are you sure you want to delete menu {menuName}? +msgctxt "description" +msgid "Are you sure you want to delete menu {menuName}?" +msgstr "" + +#: build/locale/src/customers/views/CustomerAddresses.json +#. [src.customers.views.3689332763] +#. defaultMessage is: +#. Are you sure you want to delete this address from users address book? +msgctxt "description" +msgid "Are you sure you want to delete this address from users address book?" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDeleteDialog/AttributeDeleteDialog.json +#. [src.attributes.components.AttributeDeleteDialog.3738429348] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {attributeName}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {attributeName}?" +msgstr "" + +#: build/locale/src/categories/components/CategoryDeleteDialog/CategoryDeleteDialog.json +#. [src.categories.components.CategoryDeleteDialog.847492725] - delete category +#. defaultMessage is: +#. Are you sure you want to delete {categoryName}? +msgctxt "delete category" +msgid "Are you sure you want to delete {categoryName}?" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.847492725] +#. defaultMessage is: +#. Are you sure you want to delete {categoryName}? +msgctxt "description" +msgid "Are you sure you want to delete {categoryName}?" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.523939418] +#. defaultMessage is: +#. Are you sure you want to delete {collectionName}? +msgctxt "description" +msgid "Are you sure you want to delete {collectionName}?" +msgstr "" + +#: build/locale/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.json +#. [src.attributes.components.AttributeBulkDeleteDialog.2916860383] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} attributes}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} attributes}}?" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.299584400] +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}? +#: build/locale/src/categories/views/CategoryList.json +#. [src.categories.views.844574071] +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}? +msgctxt "description" +msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.3231188861] +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}? +msgctxt "description" +msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}?" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.2497542455] +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}? +msgctxt "description" +msgid "Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}?" +msgstr "" + +#: build/locale/src/customers/views/CustomerList.json +#. [src.customers.views.409347866] +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this customer} other{{displayQuantity} customers}}? +msgctxt "description" +msgid "Are you sure you want to delete {counter,plural,one{this customer} other{{displayQuantity} customers}}?" +msgstr "" + +#: build/locale/src/navigation/views/MenuList.json +#. [menuListDeleteMenusContent] +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this menu} other{{displayQuantity} menus}}? +msgctxt "description" +msgid "Are you sure you want to delete {counter,plural,one{this menu} other{{displayQuantity} menus}}?" +msgstr "" + +#: build/locale/src/orders/views/OrderDraftList.json +#. [src.orders.views.1389231130] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this order draft} other{{displayQuantity} orderDrafts}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this order draft} other{{displayQuantity} orderDrafts}}?" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.3382708469] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this page} other{{displayQuantity} pages}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this page} other{{displayQuantity} pages}}?" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeList.json +#. [src.productTypes.views.2294091098] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this product type} other{{displayQuantity} product types}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this product type} other{{displayQuantity} product types}}?" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.2742463171] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}?" +msgstr "" + +#: build/locale/src/discounts/views/SaleList.json +#. [src.discounts.views.2516361175] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this sale} other{{displayQuantity} sales}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this sale} other{{displayQuantity} sales}}?" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZonesList.json +#. [src.shipping.views.3698270769] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this shipping zone} other{{displayQuantity} shipping zones}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this shipping zone} other{{displayQuantity} shipping zones}}?" +msgstr "" + +#: build/locale/src/products/views/ProductUpdate/ProductUpdate.json +#. [src.products.views.ProductUpdate.2446451819] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this variant} other{{displayQuantity} variants}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this variant} other{{displayQuantity} variants}}?" +msgstr "" + +#: build/locale/src/discounts/views/VoucherList.json +#. [src.discounts.views.1791926983] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {counter,plural,one{this voucher} other{{displayQuantity} vouchers}}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {counter,plural,one{this voucher} other{{displayQuantity} vouchers}}?" +msgstr "" + +#: build/locale/src/customers/views/CustomerDetails.json +#. [src.customers.views.1927691511] - delete customer, dialog content +#. defaultMessage is: +#. Are you sure you want to delete {email}? +msgctxt "delete customer, dialog content" +msgid "Are you sure you want to delete {email}?" +msgstr "" + +#: build/locale/src/navigation/views/MenuList.json +#. [menuListDeleteMenuContent] +#. defaultMessage is: +#. Are you sure you want to delete {menuName}? +msgctxt "description" +msgid "Are you sure you want to delete {menuName}?" +msgstr "" + +#: build/locale/src/components/DeleteFilterTabDialog/DeleteFilterTabDialog.json +#. [src.components.DeleteFilterTabDialog.71479100] +#. defaultMessage is: +#. Are you sure you want to delete {name} search tab? +msgctxt "description" +msgid "Are you sure you want to delete {name} search tab?" +msgstr "" + +#: build/locale/src/products/components/ProductVariantDeleteDialog/ProductVariantDeleteDialog.json +#. [src.products.components.ProductVariantDeleteDialog.2297471173] - delete product variant +#. defaultMessage is: +#. Are you sure you want to delete {name}? +msgctxt "delete product variant" +msgid "Are you sure you want to delete {name}?" +msgstr "" + +#: build/locale/src/products/views/ProductUpdate/ProductUpdate.json +#. [src.products.views.ProductUpdate.2297471173] - delete product +#. defaultMessage is: +#. Are you sure you want to delete {name}? +msgctxt "delete product" +msgid "Are you sure you want to delete {name}?" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeDeleteDialog/ProductTypeDeleteDialog.json +#. [src.productTypes.components.ProductTypeDeleteDialog.2297471173] - delete product type +#. defaultMessage is: +#. Are you sure you want to delete {name}? +msgctxt "delete product type" +msgid "Are you sure you want to delete {name}?" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.json +#. [shippingZoneDetailsDialogsDeleteShippingMethod] - delete shipping method +#. defaultMessage is: +#. Are you sure you want to delete {name}? +msgctxt "delete shipping method" +msgid "Are you sure you want to delete {name}?" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.json +#. [shippingZoneDetailsDialogsDeleteShippingZone] - delete shipping zone +#. defaultMessage is: +#. Are you sure you want to delete {name}? +msgctxt "delete shipping zone" +msgid "Are you sure you want to delete {name}?" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.1457489953] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {saleName}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {saleName}?" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZonesList.json +#. [src.shipping.views.1005071028] +#. defaultMessage is: +#. Are you sure you want to delete {shippingZoneName} shipping zone? +msgctxt "description" +msgid "Are you sure you want to delete {shippingZoneName} shipping zone?" +msgstr "" + +#: build/locale/src/pages/views/PageDetails.json +#. [src.pages.views.754348000] - delete page +#. defaultMessage is: +#. Are you sure you want to delete {title}? +msgctxt "delete page" +msgid "Are you sure you want to delete {title}?" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.3261917848] - dialog content +#. defaultMessage is: +#. Are you sure you want to delete {voucherCode}? +msgctxt "dialog content" +msgid "Are you sure you want to delete {voucherCode}?" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.1489195029] +#. defaultMessage is: +#. Are you sure you want to finalize draft #{number}? +msgctxt "description" +msgid "Are you sure you want to finalize draft #{number}?" +msgstr "" + +#: build/locale/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.json +#. [src.orders.components.OrderMarkAsPaidDialog.2823153104] +#. defaultMessage is: +#. Are you sure you want to mark this order as paid? +msgctxt "description" +msgid "Are you sure you want to mark this order as paid?" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.1348793822] +#. defaultMessage is: +#. Are you sure you want to publish {counter,plural,one{this collection} other{{displayQuantity} collections}}? +msgctxt "description" +msgid "Are you sure you want to publish {counter,plural,one{this collection} other{{displayQuantity} collections}}?" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.504298570] - dialog content +#. defaultMessage is: +#. Are you sure you want to publish {counter,plural,one{this page} other{{displayQuantity} pages}}? +msgctxt "dialog content" +msgid "Are you sure you want to publish {counter,plural,one{this page} other{{displayQuantity} pages}}?" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.740606822] - dialog content +#. defaultMessage is: +#. Are you sure you want to publish {counter,plural,one{this product} other{{displayQuantity} products}}? +msgctxt "dialog content" +msgid "Are you sure you want to publish {counter,plural,one{this product} other{{displayQuantity} products}}?" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftCancelDialog/OrderDraftCancelDialog.json +#. [src.orders.components.OrderDraftCancelDialog.3199827590] +#. defaultMessage is: +#. Are you sure you want to remove draft #{number}? +msgctxt "description" +msgid "Are you sure you want to remove draft #{number}?" +msgstr "" + +#: build/locale/src/products/views/ProductImage.json +#. [src.products.views.672103788] +#. defaultMessage is: +#. Are you sure you want to remove this image? +msgctxt "description" +msgid "Are you sure you want to remove this image?" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.json +#. [src.shipping.views.ShippingZoneDetails.1790261672] - unassign country +#. defaultMessage is: +#. Are you sure you want to remove {countryName} from this shipping zone? +msgctxt "unassign country" +msgid "Are you sure you want to remove {countryName} from this shipping zone?" +msgstr "" + +#: build/locale/src/staff/views/StaffDetails.json +#. [src.staff.views.3945766678] +#. defaultMessage is: +#. Are you sure you want to remove {email} avatar? +msgctxt "description" +msgid "Are you sure you want to remove {email} avatar?" +msgstr "" + +#: build/locale/src/staff/views/StaffDetails.json +#. [src.staff.views.2728048444] +#. defaultMessage is: +#. Are you sure you want to remove {email} from staff members? +msgctxt "description" +msgid "Are you sure you want to remove {email} from staff members?" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributeUnassignDialog/ProductTypeAttributeUnassignDialog.json +#. [src.productTypes.components.ProductTypeAttributeUnassignDialog.722498450] +#. defaultMessage is: +#. Are you sure you want to unassign {attributeName} from {productTypeName}? +msgctxt "description" +msgid "Are you sure you want to unassign {attributeName} from {productTypeName}?" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.json +#. [src.productTypes.components.ProductTypeBulkAttributeUnassignDialog.2500510112] - unassign multiple attributes from product type +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this attribute} other{{displayQuantity} attributes}} from {productTypeName}? +msgctxt "unassign multiple attributes from product type" +msgid "Are you sure you want to unassign {counter,plural,one{this attribute} other{{displayQuantity} attributes}} from {productTypeName}?" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.376977560] - dialog content +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}? +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.376977560] - dialog content +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}? +msgctxt "dialog content" +msgid "Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}?" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.396618268] - dialog content +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}? +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.396618268] - dialog content +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}? +msgctxt "dialog content" +msgid "Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}?" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.1908998638] +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}? +msgctxt "description" +msgid "Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.786949385] - dialog content +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}? +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.786949385] - dialog content +#. defaultMessage is: +#. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}? +msgctxt "dialog content" +msgid "Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.3944356444] +#. defaultMessage is: +#. Are you sure you want to unpublish {counter,plural,one{this collection} other{{displayQuantity} collections}}? +msgctxt "description" +msgid "Are you sure you want to unpublish {counter,plural,one{this collection} other{{displayQuantity} collections}}?" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.691980200] - dialog content +#. defaultMessage is: +#. Are you sure you want to unpublish {counter,plural,one{this page} other{{displayQuantity} pages}}? +msgctxt "dialog content" +msgid "Are you sure you want to unpublish {counter,plural,one{this page} other{{displayQuantity} pages}}?" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.193914731] - dialog content +#. defaultMessage is: +#. Are you sure you want to unpublish {counter,plural,one{this product} other{{displayQuantity} products}}? +msgctxt "dialog content" +msgid "Are you sure you want to unpublish {counter,plural,one{this product} other{{displayQuantity} products}}?" +msgstr "" + +#: build/locale/src/orders/components/OrderPaymentVoidDialog/OrderPaymentVoidDialog.json +#. [src.orders.components.OrderPaymentVoidDialog.2217048637] +#. defaultMessage is: +#. Are you sure you want to void this payment? +msgctxt "description" +msgid "Are you sure you want to void this payment?" +msgstr "" + +#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json +#. [src.productTypes.components.AssignAttributeDialog.3922579741] - dialog header +#. defaultMessage is: +#. Assign Attribute +msgctxt "dialog header" +msgid "Assign Attribute" +msgstr "" + +#: build/locale/src/components/AssignCategoryDialog/AssignCategoryDialog.json +#. [src.components.AssignCategoryDialog.190977792] - dialog header +#. defaultMessage is: +#. Assign Categories +msgctxt "dialog header" +msgid "Assign Categories" +msgstr "" + +#: build/locale/src/components/AssignCollectionDialog/AssignCollectionDialog.json +#. [src.components.AssignCollectionDialog.3992923611] - dialog header +#. defaultMessage is: +#. Assign Collection +msgctxt "dialog header" +msgid "Assign Collection" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.json +#. [src.discounts.components.DiscountCountrySelectDialog.1585396479] - dialog header +#. defaultMessage is: +#. Assign Countries +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.1585396479] - dialog header +#. defaultMessage is: +#. Assign Countries +msgctxt "dialog header" +msgid "Assign Countries" +msgstr "" + +#: build/locale/src/components/AssignProductDialog/AssignProductDialog.json +#. [src.components.AssignProductDialog.649693468] - dialog header +#. defaultMessage is: +#. Assign Product +msgctxt "dialog header" +msgid "Assign Product" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.json +#. [src.productTypes.components.ProductTypeAttributes.1656462109] - button +#. defaultMessage is: +#. Assign attribute +msgctxt "button" +msgid "Assign attribute" +msgstr "" + +#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json +#. [src.productTypes.components.AssignAttributeDialog.2173976534] - button +#. defaultMessage is: +#. Assign attributes +msgctxt "button" +msgid "Assign attributes" +msgstr "" + +#: build/locale/src/components/AssignCategoryDialog/AssignCategoryDialog.json +#. [src.components.AssignCategoryDialog.3973677075] - button +#. defaultMessage is: +#. Assign categories +#: build/locale/src/discounts/components/DiscountCategories/DiscountCategories.json +#. [src.discounts.components.DiscountCategories.3973677075] - button +#. defaultMessage is: +#. Assign categories +msgctxt "button" +msgid "Assign categories" +msgstr "" + +#: build/locale/src/components/AssignCollectionDialog/AssignCollectionDialog.json +#. [src.components.AssignCollectionDialog.1035511604] - button +#. defaultMessage is: +#. Assign collections +#: build/locale/src/discounts/components/DiscountCollections/DiscountCollections.json +#. [src.discounts.components.DiscountCollections.1035511604] - button +#. defaultMessage is: +#. Assign collections +msgctxt "button" +msgid "Assign collections" +msgstr "" + +#: build/locale/src/components/CountryList/CountryList.json +#. [src.components.CountryList.2747492886] - button +#. defaultMessage is: +#. Assign countries +#: build/locale/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.json +#. [src.discounts.components.DiscountCountrySelectDialog.2747492886] - button +#. defaultMessage is: +#. Assign countries +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.2747492886] - button +#. defaultMessage is: +#. Assign countries +msgctxt "button" +msgid "Assign countries" +msgstr "" + +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.460524544] - button +#. defaultMessage is: +#. Assign product +msgctxt "button" +msgid "Assign product" +msgstr "" + +#: build/locale/src/components/AssignProductDialog/AssignProductDialog.json +#. [src.components.AssignProductDialog.2100305525] - button +#. defaultMessage is: +#. Assign products +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.2100305525] - button +#. defaultMessage is: +#. Assign products +msgctxt "button" +msgid "Assign products" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.3605174225] - attribute's slug short code label +#. defaultMessage is: +#. Attribute Code +msgctxt "attribute's slug short code label" +msgid "Attribute Code" +msgstr "" + +#: build/locale/src/attributes/components/AttributeList/AttributeList.json +#. [src.attributes.components.AttributeList.3605174225] +#. defaultMessage is: +#. Attribute Code +msgctxt "description" +msgid "Attribute Code" +msgstr "" + +#: build/locale/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.json +#. [src.translations.components.TranslationsProductTypesPage.2642976392] +#. defaultMessage is: +#. Attribute Name +msgctxt "description" +msgid "Attribute Name" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValues/AttributeValues.json +#. [src.attributes.components.AttributeValues.224159874] - section header +#. defaultMessage is: +#. Attribute Values +msgctxt "section header" +msgid "Attribute Values" +msgstr "" + +#: build/locale/src/attributes/views/AttributeDetails/AttributeDetails.json +#. [src.attributes.views.AttributeDetails.499456739] +#. defaultMessage is: +#. Attribute deleted +msgctxt "description" +msgid "Attribute deleted" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributeEditDialog/ProductTypeAttributeEditDialog.json +#. [src.productTypes.components.ProductTypeAttributeEditDialog.1228425832] +#. defaultMessage is: +#. Attribute name +#: build/locale/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.json +#. [src.productTypes.components.ProductTypeAttributes.1228425832] +#. defaultMessage is: +#. Attribute name +msgctxt "description" +msgid "Attribute name" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributeEditDialog/ProductTypeAttributeEditDialog.json +#. [src.productTypes.components.ProductTypeAttributeEditDialog.335542212] +#. defaultMessage is: +#. Attribute values +msgctxt "description" +msgid "Attribute values" +msgstr "" + +#: build/locale/src/intl.json +#. [src.attributes] - attributes section name +#. defaultMessage is: +#. Attributes +msgctxt "attributes section name" +msgid "Attributes" +msgstr "" + +#: build/locale/src/products/components/ProductAttributes/ProductAttributes.json +#. [src.products.components.ProductAttributes.4153345096] - product attributes, section header +#. defaultMessage is: +#. Attributes +msgctxt "product attributes, section header" +msgid "Attributes" +msgstr "" + +#: build/locale/src/attributes/views/AttributeList/AttributeList.json +#. [src.attributes.views.AttributeList.3218248395] - deleted multiple attributes +#. defaultMessage is: +#. Attributes successfully delete +msgctxt "deleted multiple attributes" +msgid "Attributes successfully delete" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.json +#. [src.siteSettings.components.SiteSettingsKeys.226491688] - section header +#. defaultMessage is: +#. Authentication Keys +msgctxt "section header" +msgid "Authentication Keys" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.json +#. [src.siteSettings.components.SiteSettingsKeys.1270286507] - authentication provider name +#. defaultMessage is: +#. Authentication Type +msgctxt "authentication provider name" +msgid "Authentication Type" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.json +#. [src.siteSettings.components.SiteSettingsPage.2824577864] +#. defaultMessage is: +#. Authentication keys +msgctxt "description" +msgid "Authentication keys" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.json +#. [src.siteSettings.components.SiteSettingsKeyDialog.3039841202] - authentication provider name +#. defaultMessage is: +#. Authentication type +msgctxt "authentication provider name" +msgid "Authentication type" +msgstr "" + +#: build/locale/src/collections/components/CollectionList/CollectionList.json +#. [src.collections.components.CollectionList.3326160357] - collection availability +#. defaultMessage is: +#. Availability +msgctxt "collection availability" +msgid "Availability" +msgstr "" + +#: build/locale/src/intl.json +#. [src.availability] +#. defaultMessage is: +#. Availability +msgctxt "description" +msgid "Availability" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.2157131639] - product status +#. defaultMessage is: +#. Available +msgctxt "product status" +msgid "Available" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.2157131639] - product variant status +#. defaultMessage is: +#. Available +msgctxt "product variant status" +msgid "Available" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.available] - filter products by stock +#. defaultMessage is: +#. Available +msgctxt "filter products by stock" +msgid "Available" +msgstr "" + +#: build/locale/src/misc.json +#. [src.babyFoodstuffs] - tax rate +#. defaultMessage is: +#. Baby foodstuffs +msgctxt "tax rate" +msgid "Baby foodstuffs" +msgstr "" + +#: build/locale/src/intl.json +#. [src.back] - button +#. defaultMessage is: +#. Back +msgctxt "button" +msgid "Back" +msgstr "" + +#: build/locale/src/components/ErrorPage/ErrorPage.json +#. [src.components.ErrorPage.1723676032] - button +#. defaultMessage is: +#. Back to home +msgctxt "button" +msgid "Back to home" +msgstr "" + +#: build/locale/src/categories/components/CategoryBackground/CategoryBackground.json +#. [src.categories.components.CategoryBackground.1849089820] - section header +#. defaultMessage is: +#. Background image (optional) +#: build/locale/src/collections/components/CollectionImage/CollectionImage.json +#. [src.collections.components.CollectionImage.1849089820] - section header +#. defaultMessage is: +#. Background image (optional) +msgctxt "section header" +msgid "Background image (optional)" +msgstr "" + +#: build/locale/src/misc.json +#. [src.bikes] - tax rate +#. defaultMessage is: +#. Bikes +msgctxt "tax rate" +msgid "Bikes" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.4282475982] +#. defaultMessage is: +#. Billing Address +msgctxt "description" +msgid "Billing Address" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddresses/CustomerAddresses.json +#. [src.customers.components.CustomerAddresses.2428885633] - subsection header +#. defaultMessage is: +#. Billing address +msgctxt "subsection header" +msgid "Billing address" +msgstr "" + +#: build/locale/src/misc.json +#. [src.books] - tax rate +#. defaultMessage is: +#. Books +msgctxt "tax rate" +msgid "Books" +msgstr "" + +#: build/locale/src/intl.json +#. [src.cancel] - button +#. defaultMessage is: +#. Cancel +msgctxt "button" +msgid "Cancel" +msgstr "" + +#: build/locale/src/orders/views/OrderList/OrderList.json +#. [src.orders.views.OrderList.3528672691] - cancel orders, button +#. defaultMessage is: +#. Cancel +msgctxt "cancel orders, button" +msgid "Cancel" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.json +#. [src.orders.components.OrderFulfillmentCancelDialog.732594284] - dialog header +#. defaultMessage is: +#. Cancel Fulfillment +msgctxt "dialog header" +msgid "Cancel Fulfillment" +msgstr "" + +#: build/locale/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.json +#. [src.orders.components.OrderBulkCancelDialog.1528036340] - dialog header +#. defaultMessage is: +#. Cancel Orders +msgctxt "dialog header" +msgid "Cancel Orders" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.json +#. [src.orders.components.OrderFulfillmentCancelDialog.675709443] - button +#. defaultMessage is: +#. Cancel fulfillment +msgctxt "button" +msgid "Cancel fulfillment" +msgstr "" + +#: build/locale/src/orders/components/OrderCancelDialog/OrderCancelDialog.json +#. [src.orders.components.OrderCancelDialog.1854613983] - dialog header +#. defaultMessage is: +#. Cancel order +msgctxt "dialog header" +msgid "Cancel order" +msgstr "" + +#: build/locale/src/orders/components/OrderDetailsPage/OrderDetailsPage.json +#. [src.orders.components.OrderDetailsPage.1854613983] - button +#. defaultMessage is: +#. Cancel order +#: build/locale/src/orders/components/OrderDraftPage/OrderDraftPage.json +#. [src.orders.components.OrderDraftPage.1854613983] - button +#. defaultMessage is: +#. Cancel order +msgctxt "button" +msgid "Cancel order" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.662203348] - button +#. defaultMessage is: +#. Cancel shipment +msgctxt "button" +msgid "Cancel shipment" +msgstr "" + +#: build/locale/src/misc.json +#. [src.cancelled] - order status +#. defaultMessage is: +#. Cancelled +msgctxt "order status" +msgid "Cancelled" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.4211710217] - capture payment, button +#. defaultMessage is: +#. Capture +msgctxt "capture payment, button" +msgid "Capture" +msgstr "" + +#: build/locale/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.json +#. [src.orders.components.OrderPaymentDialog.1466130374] - dialog header +#. defaultMessage is: +#. Capture Payment +msgctxt "dialog header" +msgid "Capture Payment" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.2320183694] - order payment +#. defaultMessage is: +#. Captured amount +msgctxt "order payment" +msgid "Captured amount" +msgstr "" + +#: build/locale/src/intl.json +#. [src.catalog] +#. defaultMessage is: +#. Catalog +msgctxt "description" +msgid "Catalog" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.1005562666] - attribute's editor component +#. defaultMessage is: +#. Catalog Input type for Store Owner +msgctxt "attribute's editor component" +msgid "Catalog Input type for Store Owner" +msgstr "" + +#: build/locale/src/intl.json +#. [src.categories] - categories section name +#. defaultMessage is: +#. Categories +msgctxt "categories section name" +msgid "Categories" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.3583204912] +#. defaultMessage is: +#. Categories +msgctxt "description" +msgid "Categories" +msgstr "" + +#: build/locale/src/discounts/components/SaleDetailsPage/SaleDetailsPage.json +#. [saleDetailsPageCategoriesQuantity] - number of categories +#. defaultMessage is: +#. Categories ({quantity}) +#: build/locale/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.json +#. [src.discounts.components.VoucherDetailsPage.346170541] - number of categories +#. defaultMessage is: +#. Categories ({quantity}) +msgctxt "number of categories" +msgid "Categories ({quantity})" +msgstr "" + +#: build/locale/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.json +#. [src.products.components.ProductCategoryAndCollectionsForm.1755013298] +#. defaultMessage is: +#. Category +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.1755013298] +#. defaultMessage is: +#. Category +#: build/locale/src/taxes/components/CountryTaxesPage/CountryTaxesPage.json +#. [src.taxes.components.CountryTaxesPage.1755013298] +#. defaultMessage is: +#. Category +msgctxt "description" +msgid "Category" +msgstr "" + +#: build/locale/src/categories/components/CategoryDetailsForm/CategoryDetailsForm.json +#. [src.categories.components.CategoryDetailsForm.4037703468] +#. defaultMessage is: +#. Category Description +msgctxt "description" +msgid "Category Description" +msgstr "" + +#: build/locale/src/categories/components/CategoryDetailsForm/CategoryDetailsForm.json +#. [src.categories.components.CategoryDetailsForm.1214235329] +#. defaultMessage is: +#. Category Name +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.1214235329] +#. defaultMessage is: +#. Category Name +#: build/locale/src/collections/components/CollectionList/CollectionList.json +#. [src.collections.components.CollectionList.1214235329] +#. defaultMessage is: +#. Category Name +#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json +#. [src.translations.components.TranslationsCategoriesPage.1214235329] +#. defaultMessage is: +#. Category Name +msgctxt "description" +msgid "Category Name" +msgstr "" + +#: build/locale/src/categories/views/CategoryCreate.json +#. [src.categories.views.1754466114] +#. defaultMessage is: +#. Category created +msgctxt "description" +msgid "Category created" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.2189424032] +#. defaultMessage is: +#. Category deleted +msgctxt "description" +msgid "Category deleted" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCategories/DiscountCategories.json +#. [src.discounts.components.DiscountCategories.1567318211] +#. defaultMessage is: +#. Category name +msgctxt "description" +msgid "Category name" +msgstr "" + +#: build/locale/src/staff/components/StaffProperties/StaffProperties.json +#. [src.staff.components.StaffProperties.2771097267] - button +#. defaultMessage is: +#. Change photo +msgctxt "button" +msgid "Change photo" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.224127438] - product status update notification +#. defaultMessage is: +#. Changed publication status +msgctxt "product status update notification" +msgid "Changed publication status" +msgstr "" + +#: build/locale/src/products/components/ProductPricing/ProductPricing.json +#. [src.products.components.ProductPricing.3015886868] +#. defaultMessage is: +#. Charge taxes for this item +msgctxt "description" +msgid "Charge taxes for this item" +msgstr "" + +#: build/locale/src/taxes/components/TaxConfiguration/TaxConfiguration.json +#. [src.taxes.components.TaxConfiguration.2654711891] +#. defaultMessage is: +#. Charge taxes on shipping rates +msgctxt "description" +msgid "Charge taxes on shipping rates" +msgstr "" + +#: build/locale/src/misc.json +#. [src.childrensClothing] - tax rate +#. defaultMessage is: +#. Children's clothing +msgctxt "tax rate" +msgid "Children's clothing" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.2404264158] +#. defaultMessage is: +#. Choose countries you want to add to shipping zone from list below +msgctxt "description" +msgid "Choose countries you want to add to shipping zone from list below" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.json +#. [src.discounts.components.DiscountCountrySelectDialog.2177165134] +#. defaultMessage is: +#. Choose countries, you want voucher to be limited to, from the list below +msgctxt "description" +msgid "Choose countries, you want voucher to be limited to, from the list below" +msgstr "" + +#: build/locale/src/products/components/ProductVariantImages/ProductVariantImages.json +#. [src.products.components.ProductVariantImages.989683980] - button +#. defaultMessage is: +#. Choose photos +msgctxt "button" +msgid "Choose photos" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.253031977] +#. defaultMessage is: +#. City +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.253031977] +#. defaultMessage is: +#. City +msgctxt "description" +msgid "City" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.78726751] - voucher code +#. defaultMessage is: +#. Code +#: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json +#. [src.discounts.components.VoucherSummary.78726751] - voucher code +#. defaultMessage is: +#. Code +msgctxt "voucher code" +msgid "Code" +msgstr "" + +#: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json +#. [src.translations.components.TranslationsCollectionsPage.2759199473] +#. defaultMessage is: +#. Collection Name +msgctxt "description" +msgid "Collection Name" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCollections/DiscountCollections.json +#. [src.discounts.components.DiscountCollections.3011396316] +#. defaultMessage is: +#. Collection name +msgctxt "description" +msgid "Collection name" +msgstr "" + +#: build/locale/src/intl.json +#. [src.collections] - collections section name +#. defaultMessage is: +#. Collections +msgctxt "collections section name" +msgid "Collections" +msgstr "" + +#: build/locale/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.json +#. [src.products.components.ProductCategoryAndCollectionsForm.222873645] +#. defaultMessage is: +#. Collections +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.222873645] +#. defaultMessage is: +#. Collections +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.222873645] +#. defaultMessage is: +#. Collections +msgctxt "description" +msgid "Collections" +msgstr "" + +#: build/locale/src/discounts/components/SaleDetailsPage/SaleDetailsPage.json +#. [saleDetailsPageCollectionsQuantity] - number of collections +#. defaultMessage is: +#. Collections ({quantity}) +#: build/locale/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.json +#. [src.discounts.components.VoucherDetailsPage.3673147015] - number of collections +#. defaultMessage is: +#. Collections ({quantity}) +msgctxt "number of collections" +msgid "Collections ({quantity})" +msgstr "" + +#: build/locale/src/components/ColumnPicker/ColumnPickerButton.json +#. [src.components.ColumnPicker.2539195044] - select visible columns button +#. defaultMessage is: +#. Columns +msgctxt "select visible columns button" +msgid "Columns" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.3570415321] +#. defaultMessage is: +#. Company +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.3570415321] +#. defaultMessage is: +#. Company +msgctxt "description" +msgid "Company" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.json +#. [src.siteSettings.components.SiteSettingsPage.3817101936] +#. defaultMessage is: +#. Company information +msgctxt "description" +msgid "Company information" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.json +#. [src.translations.components.TranslationsEntitiesList.49462429] +#. defaultMessage is: +#. Completed Translations +msgctxt "description" +msgid "Completed Translations" +msgstr "" + +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.2754779425] - product is configurable +#. defaultMessage is: +#. Configurable +msgctxt "product is configurable" +msgid "Configurable" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.2754779425] - product type +#. defaultMessage is: +#. Configurable +msgctxt "product type" +msgid "Configurable" +msgstr "" + +#: build/locale/src/intl.json +#. [src.configuration] - configuration section name +#. defaultMessage is: +#. Configuration +msgctxt "configuration section name" +msgid "Configuration" +msgstr "" + +#: build/locale/src/intl.json +#. [src.confirm] - button +#. defaultMessage is: +#. Confirm +msgctxt "button" +msgid "Confirm" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.1111991638] - subheader +#. defaultMessage is: +#. Contact information +msgctxt "subheader" +msgid "Contact information" +msgstr "" + +#: build/locale/src/pages/components/PageInfo/PageInfo.json +#. [src.pages.components.PageInfo.1116746286] - page content +#. defaultMessage is: +#. Content +#: build/locale/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.json +#. [src.translations.components.TranslationsPagesPage.1116746286] - page content +#. defaultMessage is: +#. Content +msgctxt "page content" +msgid "Content" +msgstr "" + +#: build/locale/src/products/components/ProductVariantPrice/ProductVariantPrice.json +#. [src.products.components.ProductVariantPrice.1416480328] +#. defaultMessage is: +#. Cost price override +msgctxt "description" +msgid "Cost price override" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.2714957902] +#. defaultMessage is: +#. Could not add note +msgctxt "description" +msgid "Could not add note" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.4199953867] +#. defaultMessage is: +#. Could not cancel fulfillment +msgctxt "description" +msgid "Could not cancel fulfillment" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.562214451] +#. defaultMessage is: +#. Could not create order line +msgctxt "description" +msgid "Could not create order line" +msgstr "" + +#: build/locale/src/siteSettings/views/index.json +#. [src.siteSettings.views.2276194921] +#. defaultMessage is: +#. Could not delete authorization key: {errorMessage} +msgctxt "description" +msgid "Could not delete authorization key: {errorMessage}" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.2205960666] +#. defaultMessage is: +#. Could not delete order line +msgctxt "description" +msgid "Could not delete order line" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.149745214] +#. defaultMessage is: +#. Could not finalize draft +msgctxt "description" +msgid "Could not finalize draft" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1096896329] +#. defaultMessage is: +#. Could not fulfill items +msgctxt "description" +msgid "Could not fulfill items" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1852833563] +#. defaultMessage is: +#. Could not mark order as paid +msgctxt "description" +msgid "Could not mark order as paid" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.553600482] +#. defaultMessage is: +#. Could not update fulfillment +msgctxt "description" +msgid "Could not update fulfillment" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.487150696] +#. defaultMessage is: +#. Could not update order line +msgctxt "description" +msgid "Could not update order line" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1708579411] +#. defaultMessage is: +#. Could not update shipping method +msgctxt "description" +msgid "Could not update shipping method" +msgstr "" + +#: build/locale/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.json +#. [src.discounts.components.VoucherDetailsPage.3109712047] - voucher country range +#. defaultMessage is: +#. Countries +msgctxt "voucher country range" +msgid "Countries" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.json +#. [src.shipping.components.ShippingZoneCreatePage.3109712047] +#. defaultMessage is: +#. Countries +#: build/locale/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.json +#. [src.shipping.components.ShippingZoneDetailsPage.3109712047] +#. defaultMessage is: +#. Countries +#: build/locale/src/shipping/components/ShippingZonesList/ShippingZonesList.json +#. [src.shipping.components.ShippingZonesList.3109712047] +#. defaultMessage is: +#. Countries +msgctxt "description" +msgid "Countries" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.json +#. [src.discounts.components.DiscountCountrySelectDialog.2777439857] - country selection +#. defaultMessage is: +#. Countries A to Z +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.2777439857] - country selection +#. defaultMessage is: +#. Countries A to Z +msgctxt "country selection" +msgid "Countries A to Z" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.1139500589] +#. defaultMessage is: +#. Country +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.1139500589] +#. defaultMessage is: +#. Country +msgctxt "description" +msgid "Country" +msgstr "" + +#: build/locale/src/taxes/components/CountryList/CountryList.json +#. [src.taxes.components.CountryList.4039455144] +#. defaultMessage is: +#. Country Code +msgctxt "description" +msgid "Country Code" +msgstr "" + +#: build/locale/src/taxes/components/CountryList/CountryList.json +#. [src.taxes.components.CountryList.577035076] +#. defaultMessage is: +#. Country Name +msgctxt "description" +msgid "Country Name" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.944851093] +#. defaultMessage is: +#. Country area +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.944851093] +#. defaultMessage is: +#. Country area +msgctxt "description" +msgid "Country area" +msgstr "" + +#: build/locale/src/attributes/components/AttributePage/AttributePage.json +#. [src.attributes.components.AttributePage.2855501559] - page title +#. defaultMessage is: +#. Create New Attribute +msgctxt "page title" +msgid "Create New Attribute" +msgstr "" + +#: build/locale/src/categories/components/CategoryCreatePage/CategoryCreatePage.json +#. [src.categories.components.CategoryCreatePage.236319840] - page header +#. defaultMessage is: +#. Create New Category +msgctxt "page header" +msgid "Create New Category" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.json +#. [src.shipping.components.ShippingZoneCreatePage.4049462680] - header +#. defaultMessage is: +#. Create New Shipping Zone +msgctxt "header" +msgid "Create New Shipping Zone" +msgstr "" + +#: build/locale/src/products/views/ProductCreate.json +#. [src.products.views.1542417144] - window title +#. defaultMessage is: +#. Create Product +msgctxt "window title" +msgid "Create Product" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeCreate.json +#. [productTypeCreateHeader] - window title +#. defaultMessage is: +#. Create Product Type +msgctxt "window title" +msgid "Create Product Type" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeCreate.json +#. [productTypeCreatePageHeader] - header +#. defaultMessage is: +#. Create Product Type +msgctxt "header" +msgid "Create Product Type" +msgstr "" + +#: build/locale/src/discounts/components/SaleCreatePage/SaleCreatePage.json +#. [src.discounts.components.SaleCreatePage.3866518732] - page header +#. defaultMessage is: +#. Create Sale +msgctxt "page header" +msgid "Create Sale" +msgstr "" + +#: build/locale/src/products/views/ProductVariantCreate.json +#. [src.products.views.2362587265] - window title +#. defaultMessage is: +#. Create Variant +msgctxt "window title" +msgid "Create Variant" +msgstr "" + +#: build/locale/src/discounts/components/VoucherCreatePage/VoucherCreatePage.json +#. [src.discounts.components.VoucherCreatePage.1357216572] - page header +#. defaultMessage is: +#. Create Voucher +msgctxt "page header" +msgid "Create Voucher" +msgstr "" + +#: build/locale/src/categories/views/CategoryCreate.json +#. [src.categories.views.1140231710] - window title +#. defaultMessage is: +#. Create category +msgctxt "window title" +msgid "Create category" +msgstr "" + +#: build/locale/src/collections/views/CollectionCreate.json +#. [src.collections.views.686910896] - window title +#. defaultMessage is: +#. Create collection +msgctxt "window title" +msgid "Create collection" +msgstr "" + +#: build/locale/src/customers/views/CustomerCreate.json +#. [src.customers.views.2859116187] - window title +#. defaultMessage is: +#. Create customer +msgctxt "window title" +msgid "Create customer" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftListPage/OrderDraftListPage.json +#. [src.orders.components.OrderDraftListPage.2826235371] - button +#. defaultMessage is: +#. Create order +#: build/locale/src/orders/components/OrderListPage/OrderListPage.json +#. [src.orders.components.OrderListPage.2826235371] - button +#. defaultMessage is: +#. Create order +msgctxt "button" +msgid "Create order" +msgstr "" + +#: build/locale/src/pages/views/PageCreate.json +#. [src.pages.views.3785394515] - header +#. defaultMessage is: +#. Create page +msgctxt "header" +msgid "Create page" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.16061680] - button +#. defaultMessage is: +#. Create rate +msgctxt "button" +msgid "Create rate" +msgstr "" + +#: build/locale/src/collections/views/CollectionCreate.json +#. [src.collections.views.1597339737] +#. defaultMessage is: +#. Created collection +msgctxt "description" +msgid "Created collection" +msgstr "" + +#: build/locale/src/navigation/views/MenuList.json +#. [menuListCreatedMenu] +#. defaultMessage is: +#. Created menu +msgctxt "description" +msgid "Created menu" +msgstr "" + +#: build/locale/src/navigation/components/MenuDetailsPage/MenuDetailsPage.json +#. [menuDetailsPageHelperText] +#. defaultMessage is: +#. Creating the navigation structure is done by dragging and dropping. Simply create a new menu item and then drag it into its destined place. You can move items inside one another to create a tree structure and drag items up and down to create a hierarchy +msgctxt "description" +msgid "Creating the navigation structure is done by dragging and dropping. Simply create a new menu item and then drag it into its destined place. You can move items inside one another to create a tree structure and drag items up and down to create a hierarchy" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.json +#. [src.shipping.components.ShippingZoneCreatePage.2364051773] +#. defaultMessage is: +#. Currently, there are no countries assigned to this shipping zone +#: build/locale/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.json +#. [src.shipping.components.ShippingZoneDetailsPage.2364051773] +#. defaultMessage is: +#. Currently, there are no countries assigned to this shipping zone +msgctxt "description" +msgid "Currently, there are no countries assigned to this shipping zone" +msgstr "" + +#: build/locale/src/components/FilterBar/FilterBar.json +#. [src.components.FilterBar.2340527467] +#. defaultMessage is: +#. Custom Filter +msgctxt "description" +msgid "Custom Filter" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.3426593715] - section header +#. defaultMessage is: +#. Customer +msgctxt "section header" +msgid "Customer" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftList/OrderDraftList.json +#. [src.orders.components.OrderDraftList.3426593715] +#. defaultMessage is: +#. Customer +msgctxt "description" +msgid "Customer" +msgstr "" + +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.3426593715] - e-mail or full name +#. defaultMessage is: +#. Customer +msgctxt "e-mail or full name" +msgid "Customer" +msgstr "" + +#: build/locale/src/customers/components/CustomerList/CustomerList.json +#. [src.customers.components.CustomerList.2339105195] +#. defaultMessage is: +#. Customer Email +msgctxt "description" +msgid "Customer Email" +msgstr "" + +#: build/locale/src/customers/components/CustomerStats/CustomerStats.json +#. [src.customers.components.CustomerStats.2543847016] - section header +#. defaultMessage is: +#. Customer History +msgctxt "section header" +msgid "Customer History" +msgstr "" + +#: build/locale/src/customers/components/CustomerList/CustomerList.json +#. [src.customers.components.CustomerList.4154265139] +#. defaultMessage is: +#. Customer Name +msgctxt "description" +msgid "Customer Name" +msgstr "" + +#: build/locale/src/customers/views/CustomerDetails.json +#. [src.customers.views.3901579344] +#. defaultMessage is: +#. Customer Removed +msgctxt "description" +msgid "Customer Removed" +msgstr "" + +#: build/locale/src/customers/views/CustomerCreate.json +#. [src.customers.views.3970234993] +#. defaultMessage is: +#. Customer created +msgctxt "description" +msgid "Customer created" +msgstr "" + +#: build/locale/src/customers/components/CustomerCreateDetails/CustomerCreateDetails.json +#. [src.customers.components.CustomerCreateDetails.4157831287] - header +#. defaultMessage is: +#. Customer overview +msgctxt "header" +msgid "Customer overview" +msgstr "" + +#: build/locale/src/customers/components/CustomerDetails/CustomerDetails.json +#. [src.customers.components.CustomerDetails.2200102325] - section subheader +#. defaultMessage is: +#. Customer since: {date} +msgctxt "section subheader" +msgid "Customer since: {date}" +msgstr "" + +#: build/locale/src/intl.json +#. [src.customers] - customers section name +#. defaultMessage is: +#. Customers +msgctxt "customers section name" +msgid "Customers" +msgstr "" + +#: build/locale/src/intl.json +#. [src.dashboard] +#. defaultMessage is: +#. Dashboard +msgctxt "description" +msgid "Dashboard" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.26409543] - attribute properties regarding dashboard +#. defaultMessage is: +#. Dashboard Properties +msgctxt "attribute properties regarding dashboard" +msgid "Dashboard Properties" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.4205493358] - order placement date +#. defaultMessage is: +#. Date +msgctxt "order placement date" +msgid "Date" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftList/OrderDraftList.json +#. [src.orders.components.OrderDraftList.4205493358] - order draft creation date +#. defaultMessage is: +#. Date +msgctxt "order draft creation date" +msgid "Date" +msgstr "" + +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.4205493358] - date when order was placed +#. defaultMessage is: +#. Date +msgctxt "date when order was placed" +msgid "Date" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.4205493358] +#. defaultMessage is: +#. Date +msgctxt "description" +msgid "Date" +msgstr "" + +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.dateFrom] - filter by date +#. defaultMessage is: +#. Date from {date} +msgctxt "filter by date" +msgid "Date from {date}" +msgstr "" + +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.dateIs] - filter by date +#. defaultMessage is: +#. Date is {date} +msgctxt "filter by date" +msgid "Date is {date}" +msgstr "" + +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.dateTo] - filter by date +#. defaultMessage is: +#. Date to {date} +msgctxt "filter by date" +msgid "Date to {date}" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddress/CustomerAddress.json +#. [src.customers.components.CustomerAddress.1224809208] +#. defaultMessage is: +#. Default Address +msgctxt "description" +msgid "Default Address" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddress/CustomerAddress.json +#. [src.customers.components.CustomerAddress.1578192486] +#. defaultMessage is: +#. Default Billing Address +msgctxt "description" +msgid "Default Billing Address" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.691600601] - attribute's label +#. defaultMessage is: +#. Default Label +msgctxt "attribute's label" +msgid "Default Label" +msgstr "" + +#: build/locale/src/attributes/components/AttributeList/AttributeList.json +#. [src.attributes.components.AttributeList.691600601] - attribute's label' +#. defaultMessage is: +#. Default Label +msgctxt "attribute's label'" +msgid "Default Label" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddress/CustomerAddress.json +#. [src.customers.components.CustomerAddress.4109348993] +#. defaultMessage is: +#. Default Shipping Address +msgctxt "description" +msgid "Default Shipping Address" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValues/AttributeValues.json +#. [src.attributes.components.AttributeValues.1397696159] - attribute values list: name column header +#. defaultMessage is: +#. Default Store View +msgctxt "attribute values list: name column header" +msgid "Default Store View" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuNavigation] +#. defaultMessage is: +#. Define how users can navigate through your store +msgctxt "description" +msgid "Define how users can navigate through your store" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuProductTypes] +#. defaultMessage is: +#. Define types of products you sell +msgctxt "description" +msgid "Define types of products you sell" +msgstr "" + +#: build/locale/src/intl.json +#. [src.delete] - button +#. defaultMessage is: +#. Delete +msgctxt "button" +msgid "Delete" +msgstr "" + +#: build/locale/src/customers/views/CustomerAddresses.json +#. [src.customers.views.2657976015] - dialog header +#. defaultMessage is: +#. Delete Address +msgctxt "dialog header" +msgid "Delete Address" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.699514132] - dialog title +#. defaultMessage is: +#. Delete Collection +msgctxt "dialog title" +msgid "Delete Collection" +msgstr "" + +#: build/locale/src/orders/views/OrderDraftList.json +#. [src.orders.views.1161115149] - dialog header +#. defaultMessage is: +#. Delete Order Drafts +msgctxt "dialog header" +msgid "Delete Order Drafts" +msgstr "" + +#: build/locale/src/pages/views/PageDetails.json +#. [src.pages.views.3246254285] - dialog header +#. defaultMessage is: +#. Delete Page +msgctxt "dialog header" +msgid "Delete Page" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.2782958373] - dialog header +#. defaultMessage is: +#. Delete Pages +msgctxt "dialog header" +msgid "Delete Pages" +msgstr "" + +#: build/locale/src/products/views/ProductUpdate/ProductUpdate.json +#. [src.products.views.ProductUpdate.879305849] - dialog header +#. defaultMessage is: +#. Delete Product +msgctxt "dialog header" +msgid "Delete Product" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeDeleteDialog/ProductTypeDeleteDialog.json +#. [src.productTypes.components.ProductTypeDeleteDialog.924066985] - dialog header +#. defaultMessage is: +#. Delete Product Type +msgctxt "dialog header" +msgid "Delete Product Type" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeList.json +#. [src.productTypes.views.4080551769] - dialog header +#. defaultMessage is: +#. Delete Product Types +msgctxt "dialog header" +msgid "Delete Product Types" +msgstr "" + +#: build/locale/src/products/views/ProductUpdate/ProductUpdate.json +#. [src.products.views.ProductUpdate.1454532689] - dialog header +#. defaultMessage is: +#. Delete Product Variants +msgctxt "dialog header" +msgid "Delete Product Variants" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.400629795] - dialog header +#. defaultMessage is: +#. Delete Products +msgctxt "dialog header" +msgid "Delete Products" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.506030254] - dialog header +#. defaultMessage is: +#. Delete Sale +msgctxt "dialog header" +msgid "Delete Sale" +msgstr "" + +#: build/locale/src/discounts/views/SaleList.json +#. [src.discounts.views.2809303671] - dialog header +#. defaultMessage is: +#. Delete Sales +msgctxt "dialog header" +msgid "Delete Sales" +msgstr "" + +#: build/locale/src/components/DeleteFilterTabDialog/DeleteFilterTabDialog.json +#. [src.components.DeleteFilterTabDialog.2173195312] - custom search delete, dialog header +#. defaultMessage is: +#. Delete Search +msgctxt "custom search delete, dialog header" +msgid "Delete Search" +msgstr "" + +#: build/locale/src/components/TableFilter/FilterChips.json +#. [src.components.TableFilter.2173195312] - button +#. defaultMessage is: +#. Delete Search +msgctxt "button" +msgid "Delete Search" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.json +#. [src.shipping.views.ShippingZoneDetails.1502359905] - dialog header +#. defaultMessage is: +#. Delete Shipping Method +msgctxt "dialog header" +msgid "Delete Shipping Method" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.json +#. [src.shipping.views.ShippingZoneDetails.1010705153] - dialog header +#. defaultMessage is: +#. Delete Shipping Zone +#: build/locale/src/shipping/views/ShippingZonesList.json +#. [src.shipping.views.1010705153] - dialog header +#. defaultMessage is: +#. Delete Shipping Zone +msgctxt "dialog header" +msgid "Delete Shipping Zone" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZonesList.json +#. [src.shipping.views.1711385401] - dialog header +#. defaultMessage is: +#. Delete Shipping Zones +msgctxt "dialog header" +msgid "Delete Shipping Zones" +msgstr "" + +#: build/locale/src/staff/views/StaffDetails.json +#. [src.staff.views.701332676] - dialog header +#. defaultMessage is: +#. Delete Staff User Avatar +msgctxt "dialog header" +msgid "Delete Staff User Avatar" +msgstr "" + +#: build/locale/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.json +#. [src.products.components.ProductVariantCreatePage.3726089650] - button +#. defaultMessage is: +#. Delete Variant +msgctxt "button" +msgid "Delete Variant" +msgstr "" + +#: build/locale/src/products/components/ProductVariantDeleteDialog/ProductVariantDeleteDialog.json +#. [src.products.components.ProductVariantDeleteDialog.3726089650] - dialog header +#. defaultMessage is: +#. Delete Variant +msgctxt "dialog header" +msgid "Delete Variant" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.895379508] - dialog header +#. defaultMessage is: +#. Delete Voucher +msgctxt "dialog header" +msgid "Delete Voucher" +msgstr "" + +#: build/locale/src/discounts/views/VoucherList.json +#. [src.discounts.views.367317371] - dialog header +#. defaultMessage is: +#. Delete Vouchers +msgctxt "dialog header" +msgid "Delete Vouchers" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDeleteDialog/AttributeDeleteDialog.json +#. [src.attributes.components.AttributeDeleteDialog.1889602489] - dialog title +#. defaultMessage is: +#. Delete attribute +msgctxt "dialog title" +msgid "Delete attribute" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json +#. [src.attributes.components.AttributeValueDeleteDialog.203246037] - dialog title +#. defaultMessage is: +#. Delete attribute value +msgctxt "dialog title" +msgid "Delete attribute value" +msgstr "" + +#: build/locale/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.json +#. [src.attributes.components.AttributeBulkDeleteDialog.1655187315] - dialog title +#. defaultMessage is: +#. Delete attributes +msgctxt "dialog title" +msgid "Delete attributes" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.712767046] - dialog title +#. defaultMessage is: +#. Delete categories +#: build/locale/src/categories/views/CategoryList.json +#. [src.categories.views.712767046] - dialog title +#. defaultMessage is: +#. Delete categories +msgctxt "dialog title" +msgid "Delete categories" +msgstr "" + +#: build/locale/src/categories/components/CategoryDeleteDialog/CategoryDeleteDialog.json +#. [src.categories.components.CategoryDeleteDialog.2004894945] - dialog title +#. defaultMessage is: +#. Delete category +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.2004894945] - dialog title +#. defaultMessage is: +#. Delete category +msgctxt "dialog title" +msgid "Delete category" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.3817188998] - dialog title +#. defaultMessage is: +#. Delete collections +msgctxt "dialog title" +msgid "Delete collections" +msgstr "" + +#: build/locale/src/customers/views/CustomerDetails.json +#. [src.customers.views.442409664] - dialog header +#. defaultMessage is: +#. Delete customer +msgctxt "dialog header" +msgid "Delete customer" +msgstr "" + +#: build/locale/src/customers/views/CustomerList.json +#. [src.customers.views.1946482599] - dialog header +#. defaultMessage is: +#. Delete customers +msgctxt "dialog header" +msgid "Delete customers" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.942133001] - dialog title +#. defaultMessage is: +#. Delete image +msgctxt "dialog title" +msgid "Delete image" +msgstr "" + +#: build/locale/src/navigation/views/MenuDetails/index.json +#. [menuDetailsDeleteMenuHeader] - dialog header +#. defaultMessage is: +#. Delete menu +#: build/locale/src/navigation/views/MenuList.json +#. [menuListDeleteMenuHeader] - dialog header +#. defaultMessage is: +#. Delete menu +msgctxt "dialog header" +msgid "Delete menu" +msgstr "" + +#: build/locale/src/navigation/views/MenuList.json +#. [menuListDeleteMenusHeader] - dialog header +#. defaultMessage is: +#. Delete menus +msgctxt "dialog header" +msgid "Delete menus" +msgstr "" + +#: build/locale/src/staff/components/StaffProperties/StaffProperties.json +#. [src.staff.components.StaffProperties.457748370] - button +#. defaultMessage is: +#. Delete photo +msgctxt "button" +msgid "Delete photo" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.2507763081] - dialog title +#. defaultMessage is: +#. Delete products +msgctxt "dialog title" +msgid "Delete products" +msgstr "" + +#: build/locale/src/products/components/ProductVariantDeleteDialog/ProductVariantDeleteDialog.json +#. [src.products.components.ProductVariantDeleteDialog.1583616500] - button +#. defaultMessage is: +#. Delete variant +msgctxt "button" +msgid "Delete variant" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.1152429477] +#. defaultMessage is: +#. Deleted collection +msgctxt "description" +msgid "Deleted collection" +msgstr "" + +#: build/locale/src/navigation/views/MenuList.json +#. [menuListDeletedMenu] +#. defaultMessage is: +#. Deleted menu +msgctxt "description" +msgid "Deleted menu" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.3482612628] +#. defaultMessage is: +#. Deleted product from collection +msgctxt "description" +msgid "Deleted product from collection" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.1162257691] +#. defaultMessage is: +#. Deleted voucher +msgctxt "description" +msgid "Deleted voucher" +msgstr "" + +#: build/locale/src/intl.json +#. [src.description] +#. defaultMessage is: +#. Description +#: build/locale/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.json +#. [src.translations.components.TranslationsProductsPage.3374163063] +#. defaultMessage is: +#. Description +msgctxt "description" +msgid "Description" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuAttributes] +#. defaultMessage is: +#. Determine attributes used to create product types +msgctxt "description" +msgid "Determine attributes used to create product types" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.881286562] - product type +#. defaultMessage is: +#. Digital +msgctxt "product type" +msgid "Digital" +msgstr "" + +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsSave.json +#. [src.translations.components.TranslationFields.363646127] - button +#. defaultMessage is: +#. Discard +msgctxt "button" +msgid "Discard" +msgstr "" + +#: build/locale/src/home/components/HomeScreen.json +#. [homeScreenDisclaimer] - header +#. defaultMessage is: +#. Disclaimer +msgctxt "header" +msgid "Disclaimer" +msgstr "" + +#: build/locale/src/discounts/components/VoucherInfo/VoucherInfo.json +#. [src.discounts.components.VoucherInfo.1262795626] +#. defaultMessage is: +#. Discount Code +msgctxt "description" +msgid "Discount Code" +msgstr "" + +#: build/locale/src/discounts/components/VoucherValue/VoucherValue.json +#. [src.discounts.components.VoucherValue.1971417066] +#. defaultMessage is: +#. Discount Specific Information +msgctxt "description" +msgid "Discount Specific Information" +msgstr "" + +#: build/locale/src/discounts/components/VoucherTypes/VoucherTypes.json +#. [src.discounts.components.VoucherTypes.3216816841] - header +#. defaultMessage is: +#. Discount Type +msgctxt "header" +msgid "Discount Type" +msgstr "" + +#: build/locale/src/discounts/components/SalePricing/SalePricing.json +#. [src.discounts.components.SalePricing.1205967018] +#. defaultMessage is: +#. Discount Value +#: build/locale/src/discounts/components/VoucherValue/VoucherValue.json +#. [src.discounts.components.VoucherValue.1205967018] +#. defaultMessage is: +#. Discount Value +msgctxt "description" +msgid "Discount Value" +msgstr "" + +#: build/locale/src/intl.json +#. [src.discounts] +#. defaultMessage is: +#. Discounts +msgctxt "description" +msgid "Discounts" +msgstr "" + +#: build/locale/src/misc.json +#. [src.domesticFuel] - tax rate +#. defaultMessage is: +#. Domestic fuel +msgctxt "tax rate" +msgid "Domestic fuel" +msgstr "" + +#: build/locale/src/misc.json +#. [src.domesticServices] - tax rate +#. defaultMessage is: +#. Domestic services +msgctxt "tax rate" +msgid "Domestic services" +msgstr "" + +#: build/locale/src/components/ErrorPage/ErrorPage.json +#. [src.components.ErrorPage.3090161573] +#. defaultMessage is: +#. Don't worry, everything is gonna be fine +msgctxt "description" +msgid "Don't worry, everything is gonna be fine" +msgstr "" + +#: build/locale/src/misc.json +#. [src.draft] - order status +#. defaultMessage is: +#. Draft +msgctxt "order status" +msgid "Draft" +msgstr "" + +#: build/locale/src/intl.json +#. [src.draftOrders] - draft orders section name +#. defaultMessage is: +#. Draft Orders +msgctxt "draft orders section name" +msgid "Draft Orders" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1435191432] +#. defaultMessage is: +#. Draft order successfully finalized +msgctxt "description" +msgid "Draft order successfully finalized" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.3095247195] - order history message +#. defaultMessage is: +#. Draft order was created +msgctxt "order history message" +msgid "Draft order was created" +msgstr "" + +#: build/locale/src/intl.json +#. [src.drafts] +#. defaultMessage is: +#. Drafts +msgctxt "description" +msgid "Drafts" +msgstr "" + +#: build/locale/src/components/ImageUpload/ImageUpload.json +#. [src.components.ImageUpload.1731007575] - image upload +#. defaultMessage is: +#. Drop here to upload +msgctxt "image upload" +msgid "Drop here to upload" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.1336738461] - product attribute type +#. defaultMessage is: +#. Dropdown +msgctxt "product attribute type" +msgid "Dropdown" +msgstr "" + +#: build/locale/src/misc.json +#. [src.ebooks] - tax rate +#. defaultMessage is: +#. E-books +msgctxt "tax rate" +msgid "E-books" +msgstr "" + +#: build/locale/src/intl.json +#. [src.email] +#. defaultMessage is: +#. E-mail Address +msgctxt "description" +msgid "E-mail Address" +msgstr "" + +#: build/locale/src/intl.json +#. [src.edit] - button +#. defaultMessage is: +#. Edit +msgctxt "button" +msgid "Edit" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.json +#. [src.customers.components.CustomerAddressDialog.2364475135] - dialog title +#. defaultMessage is: +#. Edit Address +msgctxt "dialog title" +msgid "Edit Address" +msgstr "" + +#: build/locale/src/navigation/components/MenuItemDialog/MenuItemDialog.json +#. [menuItemDialogEditItem] - edit menu item, header +#. defaultMessage is: +#. Edit Item +msgctxt "edit menu item, header" +msgid "Edit Item" +msgstr "" + +#: build/locale/src/products/components/ProductImagePage/ProductImagePage.json +#. [src.products.components.ProductImagePage.2546267317] - header +#. defaultMessage is: +#. Edit Photo +msgctxt "header" +msgid "Edit Photo" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.3934114933] - dialog header +#. defaultMessage is: +#. Edit Price Rate +msgctxt "dialog header" +msgid "Edit Price Rate" +msgstr "" + +#: build/locale/src/orders/components/OrderShippingMethodEditDialog/OrderShippingMethodEditDialog.json +#. [src.orders.components.OrderShippingMethodEditDialog.3369240294] - dialog header +#. defaultMessage is: +#. Edit Shipping Method +msgctxt "dialog header" +msgid "Edit Shipping Method" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.json +#. [src.attributes.components.AttributeValueEditDialog.1395607402] - edit attribute value +#. defaultMessage is: +#. Edit Value +msgctxt "edit attribute value" +msgid "Edit Value" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.4152709923] - edit weight based shipping method, dialog header +#. defaultMessage is: +#. Edit Weight Rate +msgctxt "edit weight based shipping method, dialog header" +msgid "Edit Weight Rate" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.1703363919] - product variant attributes, button +#. defaultMessage is: +#. Edit attributes +msgctxt "product variant attributes, button" +msgid "Edit attributes" +msgstr "" + +#: build/locale/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.json +#. [src.orders.components.OrderAddressEditDialog.2935008093] - dialog header +#. defaultMessage is: +#. Edit billing address +msgctxt "dialog header" +msgid "Edit billing address" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomerEditDialog/OrderCustomerEditDialog.json +#. [src.orders.components.OrderCustomerEditDialog.1411666943] - dialog header +#. defaultMessage is: +#. Edit customer details +msgctxt "dialog header" +msgid "Edit customer details" +msgstr "" + +#: build/locale/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.json +#. [src.orders.components.OrderAddressEditDialog.462765358] - dialog header +#. defaultMessage is: +#. Edit shipping address +msgctxt "dialog header" +msgid "Edit shipping address" +msgstr "" + +#: build/locale/src/components/SeoForm/SeoForm.json +#. [src.components.SeoForm.3198271020] - button +#. defaultMessage is: +#. Edit website SEO +msgctxt "button" +msgid "Edit website SEO" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCategories/DiscountCategories.json +#. [src.discounts.components.DiscountCategories.1681512341] - section header +#. defaultMessage is: +#. Eligible Categories +msgctxt "section header" +msgid "Eligible Categories" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCollections/DiscountCollections.json +#. [src.discounts.components.DiscountCollections.452750900] - section header +#. defaultMessage is: +#. Eligible Collections +msgctxt "section header" +msgid "Eligible Collections" +msgstr "" + +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.919175218] - section header +#. defaultMessage is: +#. Eligible Products +msgctxt "section header" +msgid "Eligible Products" +msgstr "" + +#: build/locale/src/staff/components/StaffList/StaffList.json +#. [src.staff.components.StaffList.1789607185] +#. defaultMessage is: +#. Email Address +msgctxt "description" +msgid "Email Address" +msgstr "" + +#: build/locale/src/intl.json +#. [src.endDate] +#. defaultMessage is: +#. End Date +msgctxt "description" +msgid "End Date" +msgstr "" + +#: build/locale/src/intl.json +#. [src.endHour] +#. defaultMessage is: +#. End Hour +msgctxt "description" +msgid "End Hour" +msgstr "" + +#: build/locale/src/discounts/components/SaleList/SaleList.json +#. [src.discounts.components.SaleList.3715522424] - sale end date +#. defaultMessage is: +#. Ends +msgctxt "sale end date" +msgid "Ends" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.3715522424] - voucher is active until date +#. defaultMessage is: +#. Ends +msgctxt "voucher is active until date" +msgid "Ends" +msgstr "" + +#: build/locale/src/customers/components/CustomerCreateNote/CustomerCreateNote.json +#. [src.customers.components.CustomerCreateNote.932844352] +#. defaultMessage is: +#. Enter any extra infotmation regarding this customer. +msgctxt "description" +msgid "Enter any extra infotmation regarding this customer." +msgstr "" + +#: build/locale/src/discounts/translations.json +#. [src.discounts.order] - voucher discount +#. defaultMessage is: +#. Entire order +msgctxt "voucher discount" +msgid "Entire order" +msgstr "" + +#: build/locale/src/components/ConfirmButton/ConfirmButton.json +#. [src.components.ConfirmButton.2845142593] - button +#. defaultMessage is: +#. Error +msgctxt "button" +msgid "Error" +msgstr "" + +#: build/locale/src/components/ErrorMessageCard/ErrorMessageCard.json +#. [src.components.ErrorMessageCard.2845142593] - header +#. defaultMessage is: +#. Error +msgctxt "header" +msgid "Error" +msgstr "" + +#: build/locale/src/components/ErrorPage/ErrorPage.json +#. [src.components.ErrorPage.2845142593] +#. defaultMessage is: +#. Error +msgctxt "description" +msgid "Error" +msgstr "" + +#: build/locale/src/staff/components/StaffPermissions/StaffPermissions.json +#. [src.staff.components.StaffPermissions.3639008725] +#. defaultMessage is: +#. Expand or restrict user's permissions to access certain part of saleor system. +msgctxt "description" +msgid "Expand or restrict user's permissions to access certain part of saleor system." +msgstr "" + +#: build/locale/src/staff/components/StaffAddMemberDialog/StaffAddMemberDialog.json +#. [src.staff.components.StaffAddMemberDialog.351138560] +#. defaultMessage is: +#. Expand or restrict user’s permissions to access certain part of saleor system. +msgctxt "description" +msgid "Expand or restrict user’s permissions to access certain part of saleor system." +msgstr "" + +#: build/locale/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.json +#. [src.collections.components.CollectionDetailsPage.2906897537] - switch button +#. defaultMessage is: +#. Feature on Homepage +msgctxt "switch button" +msgid "Feature on Homepage" +msgstr "" + +#: build/locale/src/taxes/components/TaxConfiguration/TaxConfiguration.json +#. [src.taxes.components.TaxConfiguration.3375540052] - button +#. defaultMessage is: +#. Fetch taxes +msgctxt "button" +msgid "Fetch taxes" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.json +#. [src.discounts.components.DiscountCountrySelectDialog.2566713432] - search box label +#. defaultMessage is: +#. Filter Countries +msgctxt "search box label" +msgid "Filter Countries" +msgstr "" + +#: build/locale/src/components/FilterCard/FilterCard.json +#. [src.components.FilterCard.996289613] +#. defaultMessage is: +#. Filters +msgctxt "description" +msgid "Filters" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.2725265632] - button +#. defaultMessage is: +#. Finalize +#: build/locale/src/orders/components/OrderDraftPage/OrderDraftPage.json +#. [src.orders.components.OrderDraftPage.2725265632] - button +#. defaultMessage is: +#. Finalize +msgctxt "button" +msgid "Finalize" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.678764806] - button +#. defaultMessage is: +#. Finalize anyway +msgctxt "button" +msgid "Finalize anyway" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.845440998] - dialog header +#. defaultMessage is: +#. Finalize draft order +msgctxt "dialog header" +msgid "Finalize draft order" +msgstr "" + +#: build/locale/src/intl.json +#. [src.firstName] +#. defaultMessage is: +#. First Name +msgctxt "description" +msgid "First Name" +msgstr "" + +#: build/locale/src/discounts/components/VoucherTypes/VoucherTypes.json +#. [src.discounts.components.VoucherTypes.46415128] - voucher discount type +#. defaultMessage is: +#. Fixed Amount +msgctxt "voucher discount type" +msgid "Fixed Amount" +msgstr "" + +#: build/locale/src/misc.json +#. [src.foodstuffs] - tax rate +#. defaultMessage is: +#. Foodstuffs +msgctxt "tax rate" +msgid "Foodstuffs" +msgstr "" + +#: build/locale/src/discounts/components/VoucherTypes/VoucherTypes.json +#. [src.discounts.components.VoucherTypes.3289659291] - voucher discount type +#. defaultMessage is: +#. Free Shipping +msgctxt "voucher discount type" +msgid "Free Shipping" +msgstr "" + +#: build/locale/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.json +#. [src.orders.components.OrderUnfulfilledItems.2095687440] - button +#. defaultMessage is: +#. Fulfill +msgctxt "button" +msgid "Fulfill" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.json +#. [src.orders.components.OrderFulfillmentDialog.3236546219] - dialog header +#. defaultMessage is: +#. Fulfill products +msgctxt "dialog header" +msgid "Fulfill products" +msgstr "" + +#: build/locale/src/misc.json +#. [src.fulfilled] - order status +#. defaultMessage is: +#. Fulfilled +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.fulfilled] - order status +#. defaultMessage is: +#. Fulfilled +msgctxt "order status" +msgid "Fulfilled" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.1712863026] - order fulfillment status +#. defaultMessage is: +#. Fulfilled +msgctxt "order fulfillment status" +msgid "Fulfilled" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.3494686506] - section header +#. defaultMessage is: +#. Fulfilled ({quantity}) +msgctxt "section header" +msgid "Fulfilled ({quantity})" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.1521936480] - order history message +#. defaultMessage is: +#. Fulfilled {quantity} items +msgctxt "order history message" +msgid "Fulfilled {quantity} items" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.2943502192] - order +#. defaultMessage is: +#. Fulfillment Status +msgctxt "order" +msgid "Fulfillment Status" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.3081292385] - order history message +#. defaultMessage is: +#. Fulfillment confirmation was sent to customer +msgctxt "order history message" +msgid "Fulfillment confirmation was sent to customer" +msgstr "" + +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.1198046928] +#. defaultMessage is: +#. Fulfillment status +msgctxt "description" +msgid "Fulfillment status" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.927945225] +#. defaultMessage is: +#. Fulfillment successfully cancelled +msgctxt "description" +msgid "Fulfillment successfully cancelled" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1475565380] +#. defaultMessage is: +#. Fulfillment successfully updated +msgctxt "description" +msgid "Fulfillment successfully updated" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.1527620381] - order history message +#. defaultMessage is: +#. Fulfillment was cancelled +msgctxt "order history message" +msgid "Fulfillment was cancelled" +msgstr "" + +#: build/locale/src/misc.json +#. [src.paid] - payment status +#. defaultMessage is: +#. Fully paid +msgctxt "payment status" +msgid "Fully paid" +msgstr "" + +#: build/locale/src/misc.json +#. [src.refunded] - payment status +#. defaultMessage is: +#. Fully refunded +msgctxt "payment status" +msgid "Fully refunded" +msgstr "" + +#: build/locale/src/intl.json +#. [src.generalInformations] +#. defaultMessage is: +#. General Informations +msgctxt "description" +msgid "General Informations" +msgstr "" + +#: build/locale/src/discounts/components/VoucherInfo/VoucherInfo.json +#. [src.discounts.components.VoucherInfo.1944363009] - voucher code, button +#. defaultMessage is: +#. Generate Code +msgctxt "voucher code, button" +msgid "Generate Code" +msgstr "" + +#: build/locale/src/components/NotFoundPage/NotFoundPage.json +#. [src.components.NotFoundPage.678743710] - button +#. defaultMessage is: +#. Go back to dashboard +msgctxt "button" +msgid "Go back to dashboard" +msgstr "" + +#: build/locale/src/home/components/HomeHeader/HomeHeader.json +#. [homeHeaderText] - header +#. defaultMessage is: +#. Hello there, {userName} +#: build/locale/src/home/components/HomeScreen.json +#. [homeScreenHeader] - header +#. defaultMessage is: +#. Hello there, {userName} +msgctxt "header" +msgid "Hello there, {userName}" +msgstr "" + +#: build/locale/src/home/components/HomeHeader/HomeHeader.json +#. [homeHeaderTextCaption] - subheader +#. defaultMessage is: +#. Here is some information we gathered about your store +msgctxt "subheader" +msgid "Here is some information we gathered about your store" +msgstr "" + +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.77815154] +#. defaultMessage is: +#. Hidden +msgctxt "description" +msgid "Hidden" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.77815154] - product is hidden +#. defaultMessage is: +#. Hidden +msgctxt "product is hidden" +msgid "Hidden" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.hidden] - filter products by visibility +#. defaultMessage is: +#. Hidden +msgctxt "filter products by visibility" +msgid "Hidden" +msgstr "" + +#: build/locale/src/intl.json +#. [src.home] - home section name +#. defaultMessage is: +#. Home +msgctxt "home section name" +msgid "Home" +msgstr "" + +#: build/locale/src/misc.json +#. [src.hotels] - tax rate +#. defaultMessage is: +#. Hotels +msgctxt "tax rate" +msgid "Hotels" +msgstr "" + +#: build/locale/src/pages/components/PageSlug/PageSlug.json +#. [src.pages.components.PageSlug.4210828158] +#. defaultMessage is: +#. If empty, URL will be autogenerated from Page Name +msgctxt "description" +msgid "If empty, URL will be autogenerated from Page Name" +msgstr "" + +#: build/locale/src/components/SeoForm/SeoForm.json +#. [src.components.SeoForm.2378618579] +#. defaultMessage is: +#. If empty, the preview shows what will be autogenerated. +msgctxt "description" +msgid "If empty, the preview shows what will be autogenerated." +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.2519239682] +#. defaultMessage is: +#. If enable this attribute can be used as a column in product table. +msgctxt "description" +msgid "If enable this attribute can be used as a column in product table." +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.787251583] +#. defaultMessage is: +#. If enabled, you’ll be able to use this attribute to filter products in product list. +msgctxt "description" +msgid "If enabled, you’ll be able to use this attribute to filter products in product list." +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.1818089229] +#. defaultMessage is: +#. If selected, this will add all of the countries not selected to other shipping zones +msgctxt "description" +msgid "If selected, this will add all of the countries not selected to other shipping zones" +msgstr "" + +#: build/locale/src/discounts/components/VoucherValue/VoucherValue.json +#. [src.discounts.components.VoucherValue.4189095909] +#. defaultMessage is: +#. If this option is disabled, discount will be counted for every eligible product +msgctxt "description" +msgid "If this option is disabled, discount will be counted for every eligible product" +msgstr "" + +#: build/locale/src/staff/components/StaffStatus/StaffStatus.json +#. [src.staff.components.StaffStatus.2683780981] +#. defaultMessage is: +#. If you want to disable this account uncheck the box below +msgctxt "description" +msgid "If you want to disable this account uncheck the box below" +msgstr "" + +#: build/locale/src/products/components/ProductVariantImageSelectDialog/ProductVariantImageSelectDialog.json +#. [src.products.components.ProductVariantImageSelectDialog.3196043669] - dialog header +#. defaultMessage is: +#. Image Selection +msgctxt "dialog header" +msgid "Image Selection" +msgstr "" + +#: build/locale/src/components/RichTextEditor/ImageSource.json +#. [src.components.RichTextEditor.4035057905] +#. defaultMessage is: +#. Image URL +msgctxt "description" +msgid "Image URL" +msgstr "" + +#: build/locale/src/products/components/ProductImages/ProductImages.json +#. [src.products.components.ProductImages.3240888698] - section header +#. defaultMessage is: +#. Images +#: build/locale/src/products/components/ProductVariantImages/ProductVariantImages.json +#. [src.products.components.ProductVariantImages.3240888698] - section header +#. defaultMessage is: +#. Images +msgctxt "section header" +msgid "Images" +msgstr "" + +#: build/locale/src/staff/components/StaffList/StaffList.json +#. [src.staff.components.StaffList.1004218338] - staff member status +#. defaultMessage is: +#. Inactive +msgctxt "staff member status" +msgid "Inactive" +msgstr "" + +#: build/locale/src/products/components/ProductStock/ProductStock.json +#. [productStockHeader] - product stock, section header +#. defaultMessage is: +#. Inventory +msgctxt "product stock, section header" +msgid "Inventory" +msgstr "" + +#: build/locale/src/products/components/ProductStock/ProductStock.json +#. [prodictStockInventoryLabel] - product stock +#. defaultMessage is: +#. Inventory +msgctxt "product stock" +msgid "Inventory" +msgstr "" + +#: build/locale/src/products/components/ProductVariantStock/ProductVariantStock.json +#. [src.products.components.ProductVariantStock.3490038570] - product variant stock +#. defaultMessage is: +#. Inventory +msgctxt "product variant stock" +msgid "Inventory" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.json +#. [src.productTypes.components.ProductTypeShipping.2143413921] - switch button +#. defaultMessage is: +#. Is this product shippable? +msgctxt "switch button" +msgid "Is this product shippable?" +msgstr "" + +#: build/locale/src/navigation/components/MenuList/MenuList.json +#. [menuListItems] - number of menu items +#. defaultMessage is: +#. Items +msgctxt "number of menu items" +msgid "Items" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.4245651107] +#. defaultMessage is: +#. Items successfully fulfilled +msgctxt "description" +msgid "Items successfully fulfilled" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.json +#. [src.siteSettings.components.SiteSettingsKeyDialog.2446088470] - authentication provider API key +#. defaultMessage is: +#. Key +#: build/locale/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.json +#. [src.siteSettings.components.SiteSettingsKeys.2446088470] - authentication provider API key +#. defaultMessage is: +#. Key +msgctxt "authentication provider API key" +msgid "Key" +msgstr "" + +#: build/locale/src/translations/components/TranslationsLanguageList/TranslationsLanguageList.json +#. [src.translations.components.TranslationsLanguageList.604081953] +#. defaultMessage is: +#. Language +msgctxt "description" +msgid "Language" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.1163855804] +#. defaultMessage is: +#. Languages +#: build/locale/src/translations/components/TranslationsLanguageListPage/TranslationsLanguageListPage.json +#. [src.translations.components.TranslationsLanguageListPage.1163855804] +#. defaultMessage is: +#. Languages +msgctxt "description" +msgid "Languages" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.714411029] +#. defaultMessage is: +#. Last 30 Days +msgctxt "description" +msgid "Last 30 Days" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.3053702458] +#. defaultMessage is: +#. Last 7 Days +msgctxt "description" +msgid "Last 7 Days" +msgstr "" + +#: build/locale/src/intl.json +#. [src.lastName] +#. defaultMessage is: +#. Last Name +msgctxt "description" +msgid "Last Name" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.2292505663] +#. defaultMessage is: +#. Last Year +msgctxt "description" +msgid "Last Year" +msgstr "" + +#: build/locale/src/customers/components/CustomerStats/CustomerStats.json +#. [src.customers.components.CustomerStats.1135318032] +#. defaultMessage is: +#. Last login +msgctxt "description" +msgid "Last login" +msgstr "" + +#: build/locale/src/customers/components/CustomerStats/CustomerStats.json +#. [src.customers.components.CustomerStats.1787449306] +#. defaultMessage is: +#. Last order +msgctxt "description" +msgid "Last order" +msgstr "" + +#: build/locale/src/components/Timeline/Timeline.json +#. [src.components.Timeline.3028189627] +#. defaultMessage is: +#. Leave your note here... +msgctxt "description" +msgid "Leave your note here..." +msgstr "" + +#: build/locale/src/discounts/components/VoucherLimits/VoucherLimits.json +#. [src.discounts.components.VoucherLimits.2215544659] +#. defaultMessage is: +#. Limit number of times this discount can be used in total +msgctxt "description" +msgid "Limit number of times this discount can be used in total" +msgstr "" + +#: build/locale/src/discounts/components/VoucherLimits/VoucherLimits.json +#. [src.discounts.components.VoucherLimits.557552777] - voucher +#. defaultMessage is: +#. Limit of Uses +msgctxt "voucher" +msgid "Limit of Uses" +msgstr "" + +#: build/locale/src/discounts/components/VoucherLimits/VoucherLimits.json +#. [src.discounts.components.VoucherLimits.3459612469] - limit voucher +#. defaultMessage is: +#. Limit to one use per customer +msgctxt "limit voucher" +msgid "Limit to one use per customer" +msgstr "" + +#: build/locale/src/navigation/components/MenuItemDialog/MenuItemDialog.json +#. [menuItemDialogLinkLabel] - label +#. defaultMessage is: +#. Link +msgctxt "label" +msgid "Link" +msgstr "" + +#: build/locale/src/navigation/components/MenuItemDialog/MenuItemDialog.json +#. [menuItemDialogAddLink] - add link to navigation +#. defaultMessage is: +#. Link to: {url} +msgctxt "add link to navigation" +msgid "Link to: {url}" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.1867847329] - order history message +#. defaultMessage is: +#. Links to the order's digital goods were sent +msgctxt "order history message" +msgid "Links to the order's digital goods were sent" +msgstr "" + +#: build/locale/src/components/AppLayout/AppLayout.json +#. [src.components.AppLayout.21332146] - button +#. defaultMessage is: +#. Log out +msgctxt "button" +msgid "Log out" +msgstr "" + +#: build/locale/src/auth/components/LoginPage/LoginPage.json +#. [src.auth.components.LoginPage.109182747] - button +#. defaultMessage is: +#. Login +msgctxt "button" +msgid "Login" +msgstr "" + +#: build/locale/src/intl.json +#. [src.manage] - button +#. defaultMessage is: +#. Manage +msgctxt "button" +msgid "Manage" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuPages] +#. defaultMessage is: +#. Manage and add additional pages +msgctxt "description" +msgid "Manage and add additional pages" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuShipping] +#. defaultMessage is: +#. Manage how you ship out orders +msgctxt "description" +msgid "Manage how you ship out orders" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuTaxes] +#. defaultMessage is: +#. Manage how your store charges tax +msgctxt "description" +msgid "Manage how your store charges tax" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuStaff] +#. defaultMessage is: +#. Manage your employees and their permissions +msgctxt "description" +msgid "Manage your employees and their permissions" +msgstr "" + +#: build/locale/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.json +#. [src.orders.components.OrderMarkAsPaidDialog.4196844912] - dialog header +#. defaultMessage is: +#. Mark Order as Paid +msgctxt "dialog header" +msgid "Mark Order as Paid" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.3500506678] - order, button +#. defaultMessage is: +#. Mark as paid +msgctxt "order, button" +msgid "Mark as paid" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.3328124376] - order history message +#. defaultMessage is: +#. Marked order as paid +msgctxt "order history message" +msgid "Marked order as paid" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.3463567334] +#. defaultMessage is: +#. Maximal Order Value +msgctxt "description" +msgid "Maximal Order Value" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.3659741519] +#. defaultMessage is: +#. Maximal Order Weight +msgctxt "description" +msgid "Maximal Order Weight" +msgstr "" + +#: build/locale/src/misc.json +#. [src.medical] - tax rate +#. defaultMessage is: +#. Medical +msgctxt "tax rate" +msgid "Medical" +msgstr "" + +#: build/locale/src/navigation/components/MenuItems/MenuItems.json +#. [menuItemsHeader] - header +#. defaultMessage is: +#. Menu Items +msgctxt "header" +msgid "Menu Items" +msgstr "" + +#: build/locale/src/navigation/components/MenuCreateDialog/MenuCreateDialog.json +#. [menuCreateDialogMenuTitleLabel] +#. defaultMessage is: +#. Menu Title +#: build/locale/src/navigation/components/MenuList/MenuList.json +#. [menuListMenutitle] +#. defaultMessage is: +#. Menu Title +#: build/locale/src/navigation/components/MenuProperties/MenuProperties.json +#. [menuPropertiesMenuTitle] +#. defaultMessage is: +#. Menu Title +msgctxt "description" +msgid "Menu Title" +msgstr "" + +#: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json +#. [src.discounts.components.VoucherSummary.1836123577] - voucher value requirement +#. defaultMessage is: +#. Min. Order Value +msgctxt "voucher value requirement" +msgid "Min. Order Value" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.2427377316] - minimum amount of spent money to activate voucher +#. defaultMessage is: +#. Min. Spent +msgctxt "minimum amount of spent money to activate voucher" +msgid "Min. Spent" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1337705349] +#. defaultMessage is: +#. Minimal Order Value +msgctxt "description" +msgid "Minimal Order Value" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1878009504] +#. defaultMessage is: +#. Minimal Order Weight +msgctxt "description" +msgid "Minimal Order Weight" +msgstr "" + +#: build/locale/src/discounts/components/VoucherRequirements/VoucherRequirements.json +#. [src.discounts.components.VoucherRequirements.653777456] - voucher requirement +#. defaultMessage is: +#. Minimal order value +msgctxt "voucher requirement" +msgid "Minimal order value" +msgstr "" + +#: build/locale/src/discounts/components/VoucherRequirements/VoucherRequirements.json +#. [src.discounts.components.VoucherRequirements.2746532349] - voucher requirements, header +#. defaultMessage is: +#. Minimum Requirements +msgctxt "voucher requirements, header" +msgid "Minimum Requirements" +msgstr "" + +#: build/locale/src/discounts/components/VoucherRequirements/VoucherRequirements.json +#. [src.discounts.components.VoucherRequirements.3740704788] - voucher requirement +#. defaultMessage is: +#. Minimum quantity of items +msgctxt "voucher requirement" +msgid "Minimum quantity of items" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.3334509011] - product attribute type +#. defaultMessage is: +#. Multiple Select +msgctxt "product attribute type" +msgid "Multiple Select" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.json +#. [src.attributes.components.AttributeValueEditDialog.636461959] - attribute name +#. defaultMessage is: +#. Name +msgctxt "attribute name" +msgid "Name" +msgstr "" + +#: build/locale/src/categories/components/CategoryProducts/CategoryProducts.json +#. [src.categories.components.CategoryProducts.636461959] - product name +#. defaultMessage is: +#. Name +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.636461959] - product name +#. defaultMessage is: +#. Name +#: build/locale/src/products/components/ProductDetailsForm/ProductDetailsForm.json +#. [src.products.components.ProductDetailsForm.636461959] - product name +#. defaultMessage is: +#. Name +msgctxt "product name" +msgid "Name" +msgstr "" + +#: build/locale/src/collections/components/CollectionDetails/CollectionDetails.json +#. [src.collections.components.CollectionDetails.636461959] - collection name +#. defaultMessage is: +#. Name +msgctxt "collection name" +msgid "Name" +msgstr "" + +#: build/locale/src/components/ProductList/ProductList.json +#. [src.components.ProductList.636461959] - product +#. defaultMessage is: +#. Name +msgctxt "product" +msgid "Name" +msgstr "" + +#: build/locale/src/discounts/components/SaleInfo/SaleInfo.json +#. [src.discounts.components.SaleInfo.636461959] - sale name +#. defaultMessage is: +#. Name +#: build/locale/src/discounts/components/SaleList/SaleList.json +#. [src.discounts.components.SaleList.636461959] - sale name +#. defaultMessage is: +#. Name +#: build/locale/src/discounts/components/SaleSummary/SaleSummary.json +#. [src.discounts.components.SaleSummary.636461959] - sale name +#. defaultMessage is: +#. Name +msgctxt "sale name" +msgid "Name" +msgstr "" + +#: build/locale/src/navigation/components/MenuItemDialog/MenuItemDialog.json +#. [menuItemDialogNameLabel] - menu item name +#. defaultMessage is: +#. Name +msgctxt "menu item name" +msgid "Name" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.636461959] - product variant name +#. defaultMessage is: +#. Name +msgctxt "product variant name" +msgid "Name" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.636461959] - shipping method name +#. defaultMessage is: +#. Name +msgctxt "shipping method name" +msgid "Name" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZonesList/ShippingZonesList.json +#. [src.shipping.components.ShippingZonesList.636461959] - shipping zone +#. defaultMessage is: +#. Name +msgctxt "shipping zone" +msgid "Name" +msgstr "" + +#: build/locale/src/staff/components/StaffList/StaffList.json +#. [src.staff.components.StaffList.636461959] - staff member full name +#. defaultMessage is: +#. Name +msgctxt "staff member full name" +msgid "Name" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.json +#. [src.translations.components.TranslationsEntitiesList.636461959] - entity (product, collection, shipping method) name +#. defaultMessage is: +#. Name +msgctxt "entity (product, collection, shipping method) name" +msgid "Name" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.json +#. [src.siteSettings.components.SiteSettingsDetails.2286355060] +#. defaultMessage is: +#. Name of your store +msgctxt "description" +msgid "Name of your store" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.json +#. [src.siteSettings.components.SiteSettingsDetails.1008586926] +#. defaultMessage is: +#. Name of your store is shown on tab in web browser +msgctxt "description" +msgid "Name of your store is shown on tab in web browser" +msgstr "" + +#: build/locale/src/intl.json +#. [src.navigation] - navigation section name +#. defaultMessage is: +#. Navigation +msgctxt "navigation section name" +msgid "Navigation" +msgstr "" + +#: build/locale/src/products/views/ProductCreate.json +#. [src.products.views.1591632382] - page header +#. defaultMessage is: +#. New Product +msgctxt "page header" +msgid "New Product" +msgstr "" + +#: build/locale/src/products/components/ProductVariantNavigation/ProductVariantNavigation.json +#. [src.products.components.ProductVariantNavigation.3185562157] - variant name +#. defaultMessage is: +#. New Variant +msgctxt "variant name" +msgid "New Variant" +msgstr "" + +#: build/locale/src/misc.json +#. [src.newspapers] - tax rate +#. defaultMessage is: +#. Newspapers +msgctxt "tax rate" +msgid "Newspapers" +msgstr "" + +#: build/locale/src/intl.json +#. [src.no] +#. defaultMessage is: +#. No +msgctxt "description" +msgid "No" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.json +#. [src.orders.components.OrderDraftDetailsProducts.546865199] +#. defaultMessage is: +#. No Products added to Order +msgctxt "description" +msgid "No Products added to Order" +msgstr "" + +#: build/locale/src/home/components/HomeActivityCard/HomeActivityCard.json +#. [homeActivityCardNoActivities] +#. defaultMessage is: +#. No activities found +msgctxt "description" +msgid "No activities found" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.json +#. [src.orders.components.OrderDraftDetailsSummary.3594442178] +#. defaultMessage is: +#. No applicable shipping carriers +msgctxt "description" +msgid "No applicable shipping carriers" +msgstr "" + +#: build/locale/src/attributes/components/AttributeList/AttributeList.json +#. [src.attributes.components.AttributeList.1192828581] +#. defaultMessage is: +#. No attributes found +#: build/locale/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.json +#. [src.productTypes.components.ProductTypeAttributes.1192828581] +#. defaultMessage is: +#. No attributes found +msgctxt "description" +msgid "No attributes found" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.115822814] +#. defaultMessage is: +#. No billing address +msgctxt "description" +msgid "No billing address" +msgstr "" + +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.2054128296] +#. defaultMessage is: +#. No categories found +#: build/locale/src/discounts/components/DiscountCategories/DiscountCategories.json +#. [src.discounts.components.DiscountCategories.2054128296] +#. defaultMessage is: +#. No categories found +msgctxt "description" +msgid "No categories found" +msgstr "" + +#: build/locale/src/collections/components/CollectionList/CollectionList.json +#. [src.collections.components.CollectionList.2137803833] +#. defaultMessage is: +#. No collections found +#: build/locale/src/discounts/components/DiscountCollections/DiscountCollections.json +#. [src.discounts.components.DiscountCollections.2137803833] +#. defaultMessage is: +#. No collections found +msgctxt "description" +msgid "No collections found" +msgstr "" + +#: build/locale/src/taxes/components/CountryList/CountryList.json +#. [src.taxes.components.CountryList.110033143] +#. defaultMessage is: +#. No countries found +msgctxt "description" +msgid "No countries found" +msgstr "" + +#: build/locale/src/customers/components/CustomerList/CustomerList.json +#. [src.customers.components.CustomerList.2239722559] +#. defaultMessage is: +#. No customers found +msgctxt "description" +msgid "No customers found" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftList/OrderDraftList.json +#. [src.orders.components.OrderDraftList.2177368638] +#. defaultMessage is: +#. No draft orders found +msgctxt "description" +msgid "No draft orders found" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.json +#. [src.siteSettings.components.SiteSettingsKeys.3981699144] - no authentication provider API keys +#. defaultMessage is: +#. No keys +msgctxt "no authentication provider API keys" +msgid "No keys" +msgstr "" + +#: build/locale/src/translations/components/TranslationsLanguageList/TranslationsLanguageList.json +#. [src.translations.components.TranslationsLanguageList.2966651157] +#. defaultMessage is: +#. No languages found +msgctxt "description" +msgid "No languages found" +msgstr "" + +#: build/locale/src/navigation/components/MenuList/MenuList.json +#. [menuListNoMenus] +#. defaultMessage is: +#. No menus found +msgctxt "description" +msgid "No menus found" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomerNote/OrderCustomerNote.json +#. [src.orders.components.OrderCustomerNote.1505053535] +#. defaultMessage is: +#. No notes from customer +msgctxt "description" +msgid "No notes from customer" +msgstr "" + +#: build/locale/src/components/RowNumberSelect/RowNumberSelect.json +#. [src.components.RowNumberSelect.1154361791] +#. defaultMessage is: +#. No of Rows: +msgctxt "description" +msgid "No of Rows:" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.898333473] +#. defaultMessage is: +#. No orders found +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.898333473] +#. defaultMessage is: +#. No orders found +msgctxt "description" +msgid "No orders found" +msgstr "" + +#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json +#. [homeNotificationTableNoOrders] +#. defaultMessage is: +#. No orders ready to fulfill +msgctxt "description" +msgid "No orders ready to fulfill" +msgstr "" + +#: build/locale/src/pages/components/PageList/PageList.json +#. [src.pages.components.PageList.2489163252] +#. defaultMessage is: +#. No pages found +msgctxt "description" +msgid "No pages found" +msgstr "" + +#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json +#. [homeNotificationsNoPayments] +#. defaultMessage is: +#. No payments waiting for capture +msgctxt "description" +msgid "No payments waiting for capture" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.1126553969] +#. defaultMessage is: +#. No product types found +msgctxt "description" +msgid "No product types found" +msgstr "" + +#: build/locale/src/categories/components/CategoryProducts/CategoryProducts.json +#. [src.categories.components.CategoryProducts.1657559629] +#. defaultMessage is: +#. No products found +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.1657559629] +#. defaultMessage is: +#. No products found +#: build/locale/src/components/ProductList/ProductList.json +#. [src.components.ProductList.1657559629] +#. defaultMessage is: +#. No products found +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.1657559629] +#. defaultMessage is: +#. No products found +#: build/locale/src/home/components/HomeProductListCard/HomeProductListCard.json +#. [homeProductsListCardNoProducts] +#. defaultMessage is: +#. No products found +msgctxt "description" +msgid "No products found" +msgstr "" + +#: build/locale/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.json +#. [src.orders.components.OrderProductAddDialog.353369701] +#. defaultMessage is: +#. No products matching given query +msgctxt "description" +msgid "No products matching given query" +msgstr "" + +#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json +#. [homeNotificationsTableNoProducts] +#. defaultMessage is: +#. No products out of stock +msgctxt "description" +msgid "No products out of stock" +msgstr "" + +#: build/locale/src/taxes/components/CountryTaxesPage/CountryTaxesPage.json +#. [src.taxes.components.CountryTaxesPage.3066312070] +#. defaultMessage is: +#. No reduced tax categories found +msgctxt "description" +msgid "No reduced tax categories found" +msgstr "" + +#: build/locale/src/components/AutocompleteSelectMenu/AutocompleteSelectMenu.json +#. [src.components.AutocompleteSelectMenu.2332404293] +#. defaultMessage is: +#. No results +msgctxt "description" +msgid "No results" +msgstr "" + +#: build/locale/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.json +#. [src.components.MultiAutocompleteSelectField.4205644805] +#. defaultMessage is: +#. No results found +#: build/locale/src/components/MultiSelectField/MultiSelectField.json +#. [src.components.MultiSelectField.4205644805] +#. defaultMessage is: +#. No results found +#: build/locale/src/components/RadioGroupField/RadioGroupField.json +#. [src.components.RadioGroupField.4205644805] +#. defaultMessage is: +#. No results found +#: build/locale/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.json +#. [src.components.SingleAutocompleteSelectField.4205644805] +#. defaultMessage is: +#. No results found +#: build/locale/src/components/SingleSelectField/SingleSelectField.json +#. [src.components.SingleSelectField.4205644805] +#. defaultMessage is: +#. No results found +#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json +#. [src.productTypes.components.AssignAttributeDialog.4205644805] +#. defaultMessage is: +#. No results found +msgctxt "description" +msgid "No results found" +msgstr "" + +#: build/locale/src/discounts/components/SaleList/SaleList.json +#. [src.discounts.components.SaleList.4101565527] +#. defaultMessage is: +#. No sales found +msgctxt "description" +msgid "No sales found" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.2430492151] +#. defaultMessage is: +#. No shipping address +msgctxt "description" +msgid "No shipping address" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.1961493435] +#. defaultMessage is: +#. No shipping rates found +msgctxt "description" +msgid "No shipping rates found" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZonesList/ShippingZonesList.json +#. [src.shipping.components.ShippingZonesList.655374584] +#. defaultMessage is: +#. No shipping zones found +msgctxt "description" +msgid "No shipping zones found" +msgstr "" + +#: build/locale/src/staff/components/StaffList/StaffList.json +#. [src.staff.components.StaffList.480166346] +#. defaultMessage is: +#. No staff members found +msgctxt "description" +msgid "No staff members found" +msgstr "" + +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.2155313053] +#. defaultMessage is: +#. No subcategories found +msgctxt "description" +msgid "No subcategories found" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.json +#. [src.translations.components.TranslationsEntitiesList.4176487406] +#. defaultMessage is: +#. No translatable entities found +msgctxt "description" +msgid "No translatable entities found" +msgstr "" + +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsLong.json +#. [src.translations.components.TranslationFields.3793796047] +#. defaultMessage is: +#. No translation yet +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsRich.json +#. [src.translations.components.TranslationFields.3793796047] +#. defaultMessage is: +#. No translation yet +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsShort.json +#. [src.translations.components.TranslationFields.3793796047] +#. defaultMessage is: +#. No translation yet +msgctxt "description" +msgid "No translation yet" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.1297434244] +#. defaultMessage is: +#. No user information +msgctxt "description" +msgid "No user information" +msgstr "" + +#: build/locale/src/attributes/components/AttributeValues/AttributeValues.json +#. [src.attributes.components.AttributeValues.2054206599] - No attribute values found +#. defaultMessage is: +#. No values found +msgctxt "No attribute values found" +msgid "No values found" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.79160621] +#. defaultMessage is: +#. No vouchers found +msgctxt "description" +msgid "No vouchers found" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.2889196282] - number of order +#. defaultMessage is: +#. No. of Order +msgctxt "number of order" +msgid "No. of Order" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftList/OrderDraftList.json +#. [src.orders.components.OrderDraftList.2889196282] +#. defaultMessage is: +#. No. of Order +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.2889196282] +#. defaultMessage is: +#. No. of Order +msgctxt "description" +msgid "No. of Order" +msgstr "" + +#: build/locale/src/customers/components/CustomerList/CustomerList.json +#. [src.customers.components.CustomerList.1432565772] +#. defaultMessage is: +#. No. of Orders +msgctxt "description" +msgid "No. of Orders" +msgstr "" + +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.2527742754] - number of products +#. defaultMessage is: +#. No. of Products +msgctxt "number of products" +msgid "No. of Products" +msgstr "" + +#: build/locale/src/collections/components/CollectionList/CollectionList.json +#. [src.collections.components.CollectionList.2527742754] +#. defaultMessage is: +#. No. of Products +msgctxt "description" +msgid "No. of Products" +msgstr "" + +#: build/locale/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.json +#. [src.components.SingleAutocompleteSelectField.3069107721] +#. defaultMessage is: +#. None +msgctxt "description" +msgid "None" +msgstr "" + +#: build/locale/src/discounts/components/VoucherRequirements/VoucherRequirements.json +#. [src.discounts.components.VoucherRequirements.3069107721] - voucher has no requirements +#. defaultMessage is: +#. None +msgctxt "voucher has no requirements" +msgid "None" +msgstr "" + +#: build/locale/src/pages/components/PageList/PageList.json +#. [src.pages.components.PageList.3767550649] - page status +#. defaultMessage is: +#. Not Published +msgctxt "page status" +msgid "Not Published" +msgstr "" + +#: build/locale/src/collections/components/CollectionList/CollectionList.json +#. [src.collections.components.CollectionList.2341910657] - collection is not published +#. defaultMessage is: +#. Not published +msgctxt "collection is not published" +msgid "Not published" +msgstr "" + +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.2341910657] - product is not published +#. defaultMessage is: +#. Not published +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.2341910657] - product is not published +#. defaultMessage is: +#. Not published +msgctxt "product is not published" +msgid "Not published" +msgstr "" + +#: build/locale/src/components/ProductList/ProductList.json +#. [src.components.ProductList.2341910657] - product status +#. defaultMessage is: +#. Not published +msgctxt "product status" +msgid "Not published" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [orderCustomerCustomerNotSet] - customer is not set in draft order +#. defaultMessage is: +#. Not set +msgctxt "customer is not set in draft order" +msgid "Not set" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [orderCustomerShippingAddressNotSet] - shipping address is not set in draft order +#. defaultMessage is: +#. Not set +msgctxt "shipping address is not set in draft order" +msgid "Not set" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [orderCustomerBillingAddressNotSet] - no address is set in draft order +#. defaultMessage is: +#. Not set +msgctxt "no address is set in draft order" +msgid "Not set" +msgstr "" + +#: build/locale/src/customers/components/CustomerCreateNote/CustomerCreateNote.json +#. [src.customers.components.CustomerCreateNote.577013340] - note about customer +#. defaultMessage is: +#. Note +#: build/locale/src/customers/components/CustomerDetails/CustomerDetails.json +#. [src.customers.components.CustomerDetails.577013340] - note about customer +#. defaultMessage is: +#. Note +msgctxt "note about customer" +msgid "Note" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.3178394068] +#. defaultMessage is: +#. Note successfully added +msgctxt "description" +msgid "Note successfully added" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2304318421] - order history message +#. defaultMessage is: +#. Note was added to the order +msgctxt "order history message" +msgid "Note was added to the order" +msgstr "" + +#: build/locale/src/customers/components/CustomerCreateNote/CustomerCreateNote.json +#. [src.customers.components.CustomerCreateNote.1520756907] - notes about customer header +#. defaultMessage is: +#. Notes +msgctxt "notes about customer header" +msgid "Notes" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomerNote/OrderCustomerNote.json +#. [src.orders.components.OrderCustomerNote.1520756907] - notes about customer, header +#. defaultMessage is: +#. Notes +msgctxt "notes about customer, header" +msgid "Notes" +msgstr "" + +#: build/locale/src/discounts/components/VoucherValue/VoucherValue.json +#. [src.discounts.components.VoucherValue.1492866942] - voucher application, switch button +#. defaultMessage is: +#. Only once per order +msgctxt "voucher application, switch button" +msgid "Only once per order" +msgstr "" + +#: build/locale/src/components/ErrorPage/ErrorPage.json +#. [src.components.ErrorPage.2736139139] +#. defaultMessage is: +#. Ooops!... +#: build/locale/src/components/NotFoundPage/NotFoundPage.json +#. [src.components.NotFoundPage.2736139139] +#. defaultMessage is: +#. Ooops!... +msgctxt "description" +msgid "Ooops!..." +msgstr "" + +#: build/locale/src/intl.json +#. [src.optionalField] - field is optional +#. defaultMessage is: +#. Optional +#: build/locale/src/products/components/ProductImagePage/ProductImagePage.json +#. [src.products.components.ProductImagePage.1905082483] - field is optional +#. defaultMessage is: +#. Optional +msgctxt "field is optional" +msgid "Optional" +msgstr "" + +#: build/locale/src/products/components/ProductVariantPrice/ProductVariantPrice.json +#. [productVariantPriceOptionalPriceOverrideField] - optional field +#. defaultMessage is: +#. Optional +#: build/locale/src/products/components/ProductVariantPrice/ProductVariantPrice.json +#. [productVariantPriceOptionalCostPriceField] - optional field +#. defaultMessage is: +#. Optional +msgctxt "optional field" +msgid "Optional" +msgstr "" + +#: build/locale/src/home/components/HomeActivityCard/activityMessages.json +#. [src.home.components.HomeActivityCard.paid] +#. defaultMessage is: +#. Order #{orderId} was fully paid +msgctxt "description" +msgid "Order #{orderId} was fully paid" +msgstr "" + +#: build/locale/src/home/components/HomeActivityCard/activityMessages.json +#. [src.home.components.HomeActivityCard.placed] +#. defaultMessage is: +#. Order #{orderId} was placed +msgctxt "description" +msgid "Order #{orderId} was placed" +msgstr "" + +#: build/locale/src/home/components/HomeActivityCard/activityMessages.json +#. [src.home.components.HomeActivityCard.draft] +#. defaultMessage is: +#. Order #{orderId} was placed from draft by {userEmail} +msgctxt "description" +msgid "Order #{orderId} was placed from draft by {userEmail}" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetails/OrderDraftDetails.json +#. [src.orders.components.OrderDraftDetails.2343989342] - section header +#. defaultMessage is: +#. Order Details +msgctxt "section header" +msgid "Order Details" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.3990160018] +#. defaultMessage is: +#. Order History +msgctxt "description" +msgid "Order History" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.1230178536] - order history message +#. defaultMessage is: +#. Order address was updated +msgctxt "order history message" +msgid "Order address was updated" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2369495522] - order history message +#. defaultMessage is: +#. Order confirmation was sent to customer +msgctxt "order history message" +msgid "Order confirmation was sent to customer" +msgstr "" + +#: build/locale/src/orders/views/OrderDraftList.json +#. [src.orders.views.1872939752] +#. defaultMessage is: +#. Order draft succesfully created +#: build/locale/src/orders/views/OrderList/OrderList.json +#. [src.orders.views.OrderList.1872939752] +#. defaultMessage is: +#. Order draft succesfully created +msgctxt "description" +msgid "Order draft succesfully created" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1999598492] +#. defaultMessage is: +#. Order line added +msgctxt "description" +msgid "Order line added" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1468420349] +#. defaultMessage is: +#. Order line deleted +msgctxt "description" +msgid "Order line deleted" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1632861387] +#. defaultMessage is: +#. Order line updated +msgctxt "description" +msgid "Order line updated" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1636370257] +#. defaultMessage is: +#. Order marked as paid +msgctxt "description" +msgid "Order marked as paid" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.3280942553] +#. defaultMessage is: +#. Order payment successfully voided +msgctxt "description" +msgid "Order payment successfully voided" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.2808777264] +#. defaultMessage is: +#. Order successfully cancelled +msgctxt "description" +msgid "Order successfully cancelled" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.3367579693] +#. defaultMessage is: +#. Order successfully updated +msgctxt "description" +msgid "Order successfully updated" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.950782935] - order history message +#. defaultMessage is: +#. Order was cancelled +msgctxt "order history message" +msgid "Order was cancelled" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.1964864749] - order history message +#. defaultMessage is: +#. Order was created from draft +msgctxt "order history message" +msgid "Order was created from draft" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2655541129] - order history message +#. defaultMessage is: +#. Order was fully paid +msgctxt "order history message" +msgid "Order was fully paid" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.184692906] - order history message +#. defaultMessage is: +#. Order was placed +msgctxt "order history message" +msgid "Order was placed" +msgstr "" + +#: build/locale/src/intl.json +#. [src.orders] - orders section name +#. defaultMessage is: +#. Orders +msgctxt "orders section name" +msgid "Orders" +msgstr "" + +#: build/locale/src/orders/views/OrderList/OrderList.json +#. [src.orders.views.OrderList.1136302661] +#. defaultMessage is: +#. Orders cancelled +msgctxt "description" +msgid "Orders cancelled" +msgstr "" + +#: build/locale/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.json +#. [src.products.components.ProductCategoryAndCollectionsForm.3829816432] - product organization, header +#. defaultMessage is: +#. Organization +msgctxt "product organization, header" +msgid "Organization" +msgstr "" + +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.2364184433] - section header +#. defaultMessage is: +#. Organize Product +msgctxt "section header" +msgid "Organize Product" +msgstr "" + +#: build/locale/src/translations/components/TranslationFields/TranslationFields.json +#. [src.translations.components.TranslationFields.1348655672] +#. defaultMessage is: +#. Original String +msgctxt "description" +msgid "Original String" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1640493122] - product status +#. defaultMessage is: +#. Out Of Stock +msgctxt "product status" +msgid "Out Of Stock" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.outOfStock] - filter products by stock +#. defaultMessage is: +#. Out of stock +msgctxt "filter products by stock" +msgid "Out of stock" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.353147224] - order payment +#. defaultMessage is: +#. Outstanding Balance +msgctxt "order payment" +msgid "Outstanding Balance" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.4015160303] - order history message +#. defaultMessage is: +#. Oversold {quantity} items +msgctxt "order history message" +msgid "Oversold {quantity} items" +msgstr "" + +#: build/locale/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.json +#. [src.translations.components.TranslationsPagesPage.432157284] +#. defaultMessage is: +#. Page Title +msgctxt "description" +msgid "Page Title" +msgstr "" + +#: build/locale/src/intl.json +#. [src.pages] - pages section name +#. defaultMessage is: +#. Pages +msgctxt "pages section name" +msgid "Pages" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.3287512325] +#. defaultMessage is: +#. Pages +msgctxt "description" +msgid "Pages" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.210276526] - order fulfillment status +#. defaultMessage is: +#. Partially Fulfilled +msgctxt "order fulfillment status" +msgid "Partially Fulfilled" +msgstr "" + +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.partiallyFulfilled] - order status +#. defaultMessage is: +#. Partially Fulfilled +msgctxt "order status" +msgid "Partially Fulfilled" +msgstr "" + +#: build/locale/src/misc.json +#. [src.partiallyFulfilled] - order status +#. defaultMessage is: +#. Partially fulfilled +msgctxt "order status" +msgid "Partially fulfilled" +msgstr "" + +#: build/locale/src/misc.json +#. [src.partiallyPaid] - payment status +#. defaultMessage is: +#. Partially paid +msgctxt "payment status" +msgid "Partially paid" +msgstr "" + +#: build/locale/src/misc.json +#. [src.partiallyRefunded] - payment status +#. defaultMessage is: +#. Partially refunded +msgctxt "payment status" +msgid "Partially refunded" +msgstr "" + +#: build/locale/src/misc.json +#. [src.passengerTransport] - tax rate +#. defaultMessage is: +#. Passenger transport +msgctxt "tax rate" +msgid "Passenger transport" +msgstr "" + +#: build/locale/src/auth/components/LoginPage/LoginPage.json +#. [src.auth.components.LoginPage.2237029987] +#. defaultMessage is: +#. Password +#: build/locale/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.json +#. [src.siteSettings.components.SiteSettingsKeyDialog.2237029987] +#. defaultMessage is: +#. Password +msgctxt "description" +msgid "Password" +msgstr "" + +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.2743232155] - payment status +#. defaultMessage is: +#. Payment +msgctxt "payment status" +msgid "Payment" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2020753264] - order history message +#. defaultMessage is: +#. Payment confirmation was sent to customer +msgctxt "order history message" +msgid "Payment confirmation was sent to customer" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.4266665081] - order history message +#. defaultMessage is: +#. Payment failed +msgctxt "order history message" +msgid "Payment failed" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.557535634] +#. defaultMessage is: +#. Payment not captured: {errorMessage} +msgctxt "description" +msgid "Payment not captured: {errorMessage}" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.3991286734] - notification +#. defaultMessage is: +#. Payment not refunded: {errorMessage} +msgctxt "notification" +msgid "Payment not refunded: {errorMessage}" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.1056718390] +#. defaultMessage is: +#. Payment successfully captured +msgctxt "description" +msgid "Payment successfully captured" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.667274681] +#. defaultMessage is: +#. Payment successfully refunded +msgctxt "description" +msgid "Payment successfully refunded" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2770854455] - order history message +#. defaultMessage is: +#. Payment was captured +msgctxt "order history message" +msgid "Payment was captured" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.348557206] - order history message +#. defaultMessage is: +#. Payment was refunded +msgctxt "order history message" +msgid "Payment was refunded" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2566971846] - order history message +#. defaultMessage is: +#. Payment was voided +msgctxt "order history message" +msgid "Payment was voided" +msgstr "" + +#: build/locale/src/discounts/components/VoucherTypes/VoucherTypes.json +#. [src.discounts.components.VoucherTypes.3688224049] - voucher discount type +#. defaultMessage is: +#. Percentage +msgctxt "voucher discount type" +msgid "Percentage" +msgstr "" + +#: build/locale/src/staff/components/StaffAddMemberDialog/StaffAddMemberDialog.json +#. [src.staff.components.StaffAddMemberDialog.2690176844] +#. defaultMessage is: +#. Permissions +msgctxt "description" +msgid "Permissions" +msgstr "" + +#: build/locale/src/staff/components/StaffPermissions/StaffPermissions.json +#. [src.staff.components.StaffPermissions.2690176844] - dialog header +#. defaultMessage is: +#. Permissions +msgctxt "dialog header" +msgid "Permissions" +msgstr "" + +#: build/locale/src/misc.json +#. [src.pharmaceuticals] - tax rate +#. defaultMessage is: +#. Pharmaceuticals +msgctxt "tax rate" +msgid "Pharmaceuticals" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.1271289966] +#. defaultMessage is: +#. Phone +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.1271289966] +#. defaultMessage is: +#. Phone +msgctxt "description" +msgid "Phone" +msgstr "" + +#: build/locale/src/products/components/ProductImagePage/ProductImagePage.json +#. [src.products.components.ProductImagePage.3822382625] - section header +#. defaultMessage is: +#. Photo Information +msgctxt "section header" +msgid "Photo Information" +msgstr "" + +#: build/locale/src/products/components/ProductImagePage/ProductImagePage.json +#. [src.products.components.ProductImagePage.367472710] - section header +#. defaultMessage is: +#. Photo View +msgctxt "section header" +msgid "Photo View" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.966610541] - product type +#. defaultMessage is: +#. Physical +msgctxt "product type" +msgid "Physical" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.3590282519] - attribute position in storefront filters +#. defaultMessage is: +#. Position in faceted navigation +msgctxt "attribute position in storefront filters" +msgid "Position in faceted navigation" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.3768782744] - order payment +#. defaultMessage is: +#. Preauthorized amount +msgctxt "order payment" +msgid "Preauthorized amount" +msgstr "" + +#: build/locale/src/components/ProductList/ProductList.json +#. [src.components.ProductList.1134347598] - product +#. defaultMessage is: +#. Price +msgctxt "product" +msgid "Price" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.json +#. [src.orders.components.OrderDraftDetailsProducts.1134347598] - price or ordered products +#. defaultMessage is: +#. Price +msgctxt "price or ordered products" +msgid "Price" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.1134347598] - product price +#. defaultMessage is: +#. Price +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.1134347598] - product price +#. defaultMessage is: +#. Price +#: build/locale/src/products/components/ProductPricing/ProductPricing.json +#. [src.products.components.ProductPricing.1134347598] - product price +#. defaultMessage is: +#. Price +msgctxt "product price" +msgid "Price" +msgstr "" + +#: build/locale/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.json +#. [src.orders.components.OrderUnfulfilledItems.1134347598] - product unit price +#. defaultMessage is: +#. Price +msgctxt "product unit price" +msgid "Price" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1134347598] +#. defaultMessage is: +#. Price +msgctxt "description" +msgid "Price" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.1134347598] - product variant price +#. defaultMessage is: +#. Price +msgctxt "product variant price" +msgid "Price" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.1134347598] - shipping method price +#. defaultMessage is: +#. Price +msgctxt "shipping method price" +msgid "Price" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.2542194565] - price based shipping methods, section header +#. defaultMessage is: +#. Price Based Rates +msgctxt "price based shipping methods, section header" +msgid "Price Based Rates" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.priceFrom] - filter by price +#. defaultMessage is: +#. Price from {price} +msgctxt "filter by price" +msgid "Price from {price}" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.priceIs] - filter by price +#. defaultMessage is: +#. Price is {price} +msgctxt "filter by price" +msgid "Price is {price}" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.priceTo] - filter by price +#. defaultMessage is: +#. Price to {price} +msgctxt "filter by price" +msgid "Price to {price}" +msgstr "" + +#: build/locale/src/discounts/components/SalePricing/SalePricing.json +#. [src.discounts.components.SalePricing.1099355007] - sale pricing, header +#. defaultMessage is: +#. Pricing +msgctxt "sale pricing, header" +msgid "Pricing" +msgstr "" + +#: build/locale/src/products/components/ProductPricing/ProductPricing.json +#. [src.products.components.ProductPricing.1099355007] - product pricing +#. defaultMessage is: +#. Pricing +msgctxt "product pricing" +msgid "Pricing" +msgstr "" + +#: build/locale/src/products/components/ProductVariantPrice/ProductVariantPrice.json +#. [src.products.components.ProductVariantPrice.1099355007] - product pricing, section header +#. defaultMessage is: +#. Pricing +msgctxt "product pricing, section header" +msgid "Pricing" +msgstr "" + +#: build/locale/src/customers/components/CustomerCreateAddress/CustomerCreateAddress.json +#. [src.customers.components.CustomerCreateAddress.1922654050] - page header +#. defaultMessage is: +#. Primary address +msgctxt "page header" +msgid "Primary address" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.json +#. [src.orders.components.OrderDraftDetailsProducts.1895667608] +#. defaultMessage is: +#. Product +msgctxt "description" +msgid "Product" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.1895667608] - product name +#. defaultMessage is: +#. Product +#: build/locale/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.json +#. [src.orders.components.OrderUnfulfilledItems.1895667608] - product name +#. defaultMessage is: +#. Product +msgctxt "product name" +msgid "Product" +msgstr "" + +#: build/locale/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.json +#. [src.translations.components.TranslationsProductTypesPage.2510190956] - header +#. defaultMessage is: +#. Product Attribute ({attributeName}) +msgctxt "header" +msgid "Product Attribute ({attributeName})" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.json +#. [src.productTypes.components.ProductTypeAttributes.3559259966] - section header +#. defaultMessage is: +#. Product Attributes +msgctxt "section header" +msgid "Product Attributes" +msgstr "" + +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.2697405188] +#. defaultMessage is: +#. Product Name +#: build/locale/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.json +#. [src.translations.components.TranslationsProductsPage.2697405188] +#. defaultMessage is: +#. Product Name +msgctxt "description" +msgid "Product Name" +msgstr "" + +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.4257289053] +#. defaultMessage is: +#. Product Type +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.4257289053] +#. defaultMessage is: +#. Product Type +msgctxt "description" +msgid "Product Type" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeDetails/ProductTypeDetails.json +#. [src.productTypes.components.ProductTypeDetails.1007996279] +#. defaultMessage is: +#. Product Type Name +msgctxt "description" +msgid "Product Type Name" +msgstr "" + +#: build/locale/src/intl.json +#. [src.productTypes] - product types section name +#. defaultMessage is: +#. Product Types +msgctxt "product types section name" +msgid "Product Types" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.765385638] +#. defaultMessage is: +#. Product Types +msgctxt "description" +msgid "Product Types" +msgstr "" + +#: build/locale/src/products/views/ProductCreate.json +#. [src.products.views.2899821092] +#. defaultMessage is: +#. Product created +#: build/locale/src/products/views/ProductVariantCreate.json +#. [src.products.views.2899821092] +#. defaultMessage is: +#. Product created +msgctxt "description" +msgid "Product created" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.json +#. [src.orders.components.OrderFulfillmentDialog.4046223826] +#. defaultMessage is: +#. Product name +msgctxt "description" +msgid "Product name" +msgstr "" + +#: build/locale/src/products/views/ProductUpdate/ProductUpdate.json +#. [src.products.views.ProductUpdate.4108890645] +#. defaultMessage is: +#. Product removed +msgctxt "description" +msgid "Product removed" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeUpdate/index.json +#. [src.productTypes.views.ProductTypeUpdate.3512959355] +#. defaultMessage is: +#. Product type deleted +msgctxt "description" +msgid "Product type deleted" +msgstr "" + +#: build/locale/src/categories/components/CategoryProducts/CategoryProducts.json +#. [src.categories.components.CategoryProducts.2968663655] - section header +#. defaultMessage is: +#. Products +msgctxt "section header" +msgid "Products" +msgstr "" + +#: build/locale/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.json +#. [src.categories.components.CategoryUpdatePage.2968663655] - number of products in category +#. defaultMessage is: +#. Products +msgctxt "number of products in category" +msgid "Products" +msgstr "" + +#: build/locale/src/discounts/components/DiscountCategories/DiscountCategories.json +#. [src.discounts.components.DiscountCategories.2968663655] - number of products +#. defaultMessage is: +#. Products +#: build/locale/src/discounts/components/DiscountCollections/DiscountCollections.json +#. [src.discounts.components.DiscountCollections.2968663655] - number of products +#. defaultMessage is: +#. Products +msgctxt "number of products" +msgid "Products" +msgstr "" + +#: build/locale/src/intl.json +#. [src.products] - products section name +#. defaultMessage is: +#. Products +msgctxt "products section name" +msgid "Products" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.2968663655] +#. defaultMessage is: +#. Products +msgctxt "description" +msgid "Products" +msgstr "" + +#: build/locale/src/discounts/components/SaleDetailsPage/SaleDetailsPage.json +#. [saleDetailsPageProductsQuantity] - number of products +#. defaultMessage is: +#. Products ({quantity}) +#: build/locale/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.json +#. [src.discounts.components.VoucherDetailsPage.846927739] - number of products +#. defaultMessage is: +#. Products ({quantity}) +msgctxt "number of products" +msgid "Products ({quantity})" +msgstr "" + +#: build/locale/src/categories/components/CategoryProductsCard/CategoryProductsCard.json +#. [src.categories.components.CategoryProductsCard.4164156574] - section header +#. defaultMessage is: +#. Products in {categoryName} +msgctxt "section header" +msgid "Products in {categoryName}" +msgstr "" + +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.4114667680] - products in collection +#. defaultMessage is: +#. Products in {name} +msgctxt "products in collection" +msgid "Products in {name}" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.1694086800] +#. defaultMessage is: +#. Products removed +msgctxt "description" +msgid "Products removed" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.3506022286] - order history message +#. defaultMessage is: +#. Products were added to draft order +msgctxt "order history message" +msgid "Products were added to draft order" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2574162126] - order history message +#. defaultMessage is: +#. Products were removed from draft order +msgctxt "order history message" +msgid "Products were removed from draft order" +msgstr "" + +#: build/locale/src/intl.json +#. [src.properties] +#. defaultMessage is: +#. Properties +msgctxt "description" +msgid "Properties" +msgstr "" + +#: build/locale/src/misc.json +#. [src.propertyRenovations] - tax rate +#. defaultMessage is: +#. Property renovations +msgctxt "tax rate" +msgid "Property renovations" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.1547167026] - publish collections +#. defaultMessage is: +#. Publish +msgctxt "publish collections" +msgid "Publish" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.1547167026] - publish page, button +#. defaultMessage is: +#. Publish +msgctxt "publish page, button" +msgid "Publish" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.1547167026] - publish product, button +#. defaultMessage is: +#. Publish +msgctxt "publish product, button" +msgid "Publish" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.2321087286] - dialog header +#. defaultMessage is: +#. Publish Pages +msgctxt "dialog header" +msgid "Publish Pages" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.2946646245] - dialog header +#. defaultMessage is: +#. Publish Products +msgctxt "dialog header" +msgid "Publish Products" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.2823425739] - dialog title +#. defaultMessage is: +#. Publish collections +msgctxt "dialog title" +msgid "Publish collections" +msgstr "" + +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.2060790769] - publish on date +#. defaultMessage is: +#. Publish on +msgctxt "publish on date" +msgid "Publish on" +msgstr "" + +#: build/locale/src/collections/components/CollectionList/CollectionList.json +#. [src.collections.components.CollectionList.3640454975] - collection is published +#. defaultMessage is: +#. Published +msgctxt "collection is published" +msgid "Published" +msgstr "" + +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.3640454975] - product is published +#. defaultMessage is: +#. Published +#: build/locale/src/discounts/components/DiscountProducts/DiscountProducts.json +#. [src.discounts.components.DiscountProducts.3640454975] - product is published +#. defaultMessage is: +#. Published +msgctxt "product is published" +msgid "Published" +msgstr "" + +#: build/locale/src/components/ProductList/ProductList.json +#. [src.components.ProductList.3640454975] - product status +#. defaultMessage is: +#. Published +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.3640454975] - product status +#. defaultMessage is: +#. Published +msgctxt "product status" +msgid "Published" +msgstr "" + +#: build/locale/src/pages/components/PageList/PageList.json +#. [src.pages.components.PageList.3640454975] - page status +#. defaultMessage is: +#. Published +msgctxt "page status" +msgid "Published" +msgstr "" + +#: build/locale/src/products/views/ProductList/filters.json +#. [src.products.views.ProductList.published] - filter products by visibility +#. defaultMessage is: +#. Published +msgctxt "filter products by visibility" +msgid "Published" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.2543350562] - notification +#. defaultMessage is: +#. Published pages +msgctxt "notification" +msgid "Published pages" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.json +#. [src.orders.components.OrderDraftDetailsProducts.2796503714] - quantity of ordered products +#. defaultMessage is: +#. Quantity +msgctxt "quantity of ordered products" +msgid "Quantity" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.2796503714] - ordered product quantity +#. defaultMessage is: +#. Quantity +msgctxt "ordered product quantity" +msgid "Quantity" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.json +#. [src.orders.components.OrderFulfillmentDialog.2796503714] - quantity of fulfilled products +#. defaultMessage is: +#. Quantity +msgctxt "quantity of fulfilled products" +msgid "Quantity" +msgstr "" + +#: build/locale/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.json +#. [src.orders.components.OrderUnfulfilledItems.2796503714] - ordered products +#. defaultMessage is: +#. Quantity +msgctxt "ordered products" +msgid "Quantity" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.1440682557] +#. defaultMessage is: +#. Quick Pick +msgctxt "description" +msgid "Quick Pick" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.2545228781] +#. defaultMessage is: +#. Range +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.2545228781] +#. defaultMessage is: +#. Range +msgctxt "description" +msgid "Range" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.3213611593] - shipping method +#. defaultMessage is: +#. Rate +msgctxt "shipping method" +msgid "Rate" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.382595300] - shipping method name +#. defaultMessage is: +#. Rate Name +msgctxt "shipping method name" +msgid "Rate Name" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1403365734] - shipping method price +#. defaultMessage is: +#. Rate Price +msgctxt "shipping method price" +msgid "Rate Price" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.3878642352] - section header +#. defaultMessage is: +#. Recent orders +msgctxt "section header" +msgid "Recent orders" +msgstr "" + +#: build/locale/src/taxes/components/CountryList/CountryList.json +#. [src.taxes.components.CountryList.3154586635] +#. defaultMessage is: +#. Reduced Tax Rates +msgctxt "description" +msgid "Reduced Tax Rates" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.2845258362] - button +#. defaultMessage is: +#. Refund +msgctxt "button" +msgid "Refund" +msgstr "" + +#: build/locale/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.json +#. [src.orders.components.OrderPaymentDialog.250371749] - dialog header +#. defaultMessage is: +#. Refund Payment +msgctxt "dialog header" +msgid "Refund Payment" +msgstr "" + +#: build/locale/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.json +#. [src.orders.components.OrderBulkCancelDialog.187921539] - switch button +#. defaultMessage is: +#. Release all stock allocated to these orders +msgctxt "switch button" +msgid "Release all stock allocated to these orders" +msgstr "" + +#: build/locale/src/orders/components/OrderCancelDialog/OrderCancelDialog.json +#. [src.orders.components.OrderCancelDialog.944150063] - switch button +#. defaultMessage is: +#. Release all stock allocated to this order +msgctxt "switch button" +msgid "Release all stock allocated to this order" +msgstr "" + +#: build/locale/src/auth/components/LoginPage/LoginPage.json +#. [src.auth.components.LoginPage.3182284913] - login +#. defaultMessage is: +#. Remember me +msgctxt "login" +msgid "Remember me" +msgstr "" + +#: build/locale/src/categories/views/CategoryDetails.json +#. [src.categories.views.3488150607] +#. defaultMessage is: +#. Remember this will also delete all products assigned to this category. +#: build/locale/src/categories/views/CategoryList.json +#. [src.categories.views.3488150607] +#. defaultMessage is: +#. Remember this will also delete all products assigned to this category. +msgctxt "description" +msgid "Remember this will also delete all products assigned to this category." +msgstr "" + +#: build/locale/src/intl.json +#. [src.remove] - button +#. defaultMessage is: +#. Remove +msgctxt "button" +msgid "Remove" +msgstr "" + +#: build/locale/src/products/views/ProductImage.json +#. [src.products.views.490753666] - dialog header +#. defaultMessage is: +#. Remove Image +msgctxt "dialog header" +msgid "Remove Image" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftCancelDialog/OrderDraftCancelDialog.json +#. [src.orders.components.OrderDraftCancelDialog.500287069] - dialog header +#. defaultMessage is: +#. Remove draft order +msgctxt "dialog header" +msgid "Remove draft order" +msgstr "" + +#: build/locale/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.json +#. [src.shipping.views.ShippingZoneDetails.254167659] - unassign country, dialog header +#. defaultMessage is: +#. Remove from shipping zone +msgctxt "unassign country, dialog header" +msgid "Remove from shipping zone" +msgstr "" + +#: build/locale/src/orders/views/OrderDraftList.json +#. [src.orders.views.3880993240] +#. defaultMessage is: +#. Removed draft orders +msgctxt "description" +msgid "Removed draft orders" +msgstr "" + +#: build/locale/src/pages/views/PageDetails.json +#. [src.pages.views.1457312643] +#. defaultMessage is: +#. Removed page +msgctxt "description" +msgid "Removed page" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.1080715663] - notification +#. defaultMessage is: +#. Removed pages +msgctxt "notification" +msgid "Removed pages" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.2534378844] +#. defaultMessage is: +#. Removed sale +msgctxt "description" +msgid "Removed sale" +msgstr "" + +#: build/locale/src/components/RichTextEditor/ImageEntity.json +#. [src.components.RichTextEditor.2049070632] - replace image, button +#. defaultMessage is: +#. Replace +msgctxt "replace image, button" +msgid "Replace" +msgstr "" + +#: build/locale/src/components/ColumnPicker/ColumnPickerContent.json +#. [src.components.ColumnPicker.1483881697] - button +#. defaultMessage is: +#. Reset +msgctxt "button" +msgid "Reset" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.1003092716] +#. defaultMessage is: +#. Rest of the World +msgctxt "description" +msgid "Rest of the World" +msgstr "" + +#: build/locale/src/misc.json +#. [src.restaurants] - tax rate +#. defaultMessage is: +#. Restaurants +msgctxt "tax rate" +msgid "Restaurants" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.json +#. [src.orders.components.OrderFulfillmentCancelDialog.3515223857] - switch button +#. defaultMessage is: +#. Restock items? +msgctxt "switch button" +msgid "Restock items?" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.2027649178] - order history message +#. defaultMessage is: +#. Restocked {quantity} items +msgctxt "order history message" +msgid "Restocked {quantity} items" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.json +#. [src.orders.components.OrderFulfillmentDialog.693960049] - product's sku +#. defaultMessage is: +#. SKU +msgctxt "product's sku" +msgid "SKU" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.693960049] +#. defaultMessage is: +#. SKU +msgctxt "description" +msgid "SKU" +msgstr "" + +#: build/locale/src/products/components/ProductStock/ProductStock.json +#. [src.products.components.ProductStock.2585918415] +#. defaultMessage is: +#. SKU (Stock Keeping Unit) +#: build/locale/src/products/components/ProductVariantStock/ProductVariantStock.json +#. [src.products.components.ProductVariantStock.2585918415] +#. defaultMessage is: +#. SKU (Stock Keeping Unit) +msgctxt "description" +msgid "SKU (Stock Keeping Unit)" +msgstr "" + +#: build/locale/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.json +#. [src.orders.components.OrderProductAddDialog.2272209368] - variant sku +#. defaultMessage is: +#. SKU {sku} +msgctxt "variant sku" +msgid "SKU {sku}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsSalesPage/TranslationsSalesPage.json +#. [src.translations.components.TranslationsSalesPage.898281424] +#. defaultMessage is: +#. Sale Name +msgctxt "description" +msgid "Sale Name" +msgstr "" + +#: build/locale/src/intl.json +#. [src.sales] - sales section name +#. defaultMessage is: +#. Sales +msgctxt "sales section name" +msgid "Sales" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.487083593] +#. defaultMessage is: +#. Sales +msgctxt "description" +msgid "Sales" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.3912924864] - billing address +#. defaultMessage is: +#. Same as shipping address +msgctxt "billing address" +msgid "Same as shipping address" +msgstr "" + +#: build/locale/src/intl.json +#. [src.save] - button +#. defaultMessage is: +#. Save +msgctxt "button" +msgid "Save" +msgstr "" + +#: build/locale/src/components/SaveFilterTabDialog/SaveFilterTabDialog.json +#. [src.components.SaveFilterTabDialog.1514415736] - save filter tab, header +#. defaultMessage is: +#. Save Custom Search +msgctxt "save filter tab, header" +msgid "Save Custom Search" +msgstr "" + +#: build/locale/src/components/TableFilter/FilterChips.json +#. [src.components.TableFilter.1514415736] - button +#. defaultMessage is: +#. Save Custom Search +msgctxt "button" +msgid "Save Custom Search" +msgstr "" + +#: build/locale/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.json +#. [src.products.components.ProductVariantCreatePage.2853608829] - button +#. defaultMessage is: +#. Save variant +msgctxt "button" +msgid "Save variant" +msgstr "" + +#: build/locale/src/intl.json +#. [src.savedChanges] +#. defaultMessage is: +#. Saved changes +msgctxt "description" +msgid "Saved changes" +msgstr "" + +#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json +#. [src.productTypes.components.AssignAttributeDialog.902296540] +#. defaultMessage is: +#. Search Attributes +msgctxt "description" +msgid "Search Attributes" +msgstr "" + +#: build/locale/src/components/AssignCategoryDialog/AssignCategoryDialog.json +#. [src.components.AssignCategoryDialog.1305061437] +#. defaultMessage is: +#. Search Categories +msgctxt "description" +msgid "Search Categories" +msgstr "" + +#: build/locale/src/components/AssignCollectionDialog/AssignCollectionDialog.json +#. [src.components.AssignCollectionDialog.4057224233] +#. defaultMessage is: +#. Search Collection +msgctxt "description" +msgid "Search Collection" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.3510295703] +#. defaultMessage is: +#. Search Countries +msgctxt "description" +msgid "Search Countries" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.2433460203] +#. defaultMessage is: +#. Search Customers +msgctxt "description" +msgid "Search Customers" +msgstr "" + +#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json +#. [src.translations.components.TranslationsCategoriesPage.1406947243] +#. defaultMessage is: +#. Search Engine Description +#: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json +#. [src.translations.components.TranslationsCollectionsPage.1406947243] +#. defaultMessage is: +#. Search Engine Description +#: build/locale/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.json +#. [src.translations.components.TranslationsPagesPage.1406947243] +#. defaultMessage is: +#. Search Engine Description +#: build/locale/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.json +#. [src.translations.components.TranslationsProductsPage.1406947243] +#. defaultMessage is: +#. Search Engine Description +msgctxt "description" +msgid "Search Engine Description" +msgstr "" + +#: build/locale/src/components/SeoForm/SeoForm.json +#. [src.components.SeoForm.3468022343] +#. defaultMessage is: +#. Search Engine Preview +#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json +#. [src.translations.components.TranslationsCategoriesPage.3468022343] +#. defaultMessage is: +#. Search Engine Preview +#: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json +#. [src.translations.components.TranslationsCollectionsPage.3468022343] +#. defaultMessage is: +#. Search Engine Preview +#: build/locale/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.json +#. [src.translations.components.TranslationsPagesPage.3468022343] +#. defaultMessage is: +#. Search Engine Preview +#: build/locale/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.json +#. [src.translations.components.TranslationsProductsPage.3468022343] +#. defaultMessage is: +#. Search Engine Preview +msgctxt "description" +msgid "Search Engine Preview" +msgstr "" + +#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json +#. [src.translations.components.TranslationsCategoriesPage.2496919463] +#. defaultMessage is: +#. Search Engine Title +#: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json +#. [src.translations.components.TranslationsCollectionsPage.2496919463] +#. defaultMessage is: +#. Search Engine Title +#: build/locale/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.json +#. [src.translations.components.TranslationsPagesPage.2496919463] +#. defaultMessage is: +#. Search Engine Title +#: build/locale/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.json +#. [src.translations.components.TranslationsProductsPage.2496919463] +#. defaultMessage is: +#. Search Engine Title +msgctxt "description" +msgid "Search Engine Title" +msgstr "" + +#: build/locale/src/components/SaveFilterTabDialog/SaveFilterTabDialog.json +#. [src.components.SaveFilterTabDialog.1556856943] - save search tab +#. defaultMessage is: +#. Search Name +msgctxt "save search tab" +msgid "Search Name" +msgstr "" + +#: build/locale/src/orders/components/OrderListPage/OrderListPage.json +#. [src.orders.components.OrderListPage.355376157] +#. defaultMessage is: +#. Search Orders... +msgctxt "description" +msgid "Search Orders..." +msgstr "" + +#: build/locale/src/components/AssignProductDialog/AssignProductDialog.json +#. [src.components.AssignProductDialog.2850255786] +#. defaultMessage is: +#. Search Products +#: build/locale/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.json +#. [src.orders.components.OrderProductAddDialog.2850255786] +#. defaultMessage is: +#. Search Products +msgctxt "description" +msgid "Search Products" +msgstr "" + +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.3550330425] +#. defaultMessage is: +#. Search Products... +msgctxt "description" +msgid "Search Products..." +msgstr "" + +#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json +#. [src.productTypes.components.AssignAttributeDialog.524117994] +#. defaultMessage is: +#. Search by attribute name +msgctxt "description" +msgid "Search by attribute name" +msgstr "" + +#: build/locale/src/components/AssignCategoryDialog/AssignCategoryDialog.json +#. [src.components.AssignCategoryDialog.3690273268] +#. defaultMessage is: +#. Search by category name, etc... +msgctxt "description" +msgid "Search by category name, etc..." +msgstr "" + +#: build/locale/src/components/AssignCollectionDialog/AssignCollectionDialog.json +#. [src.components.AssignCollectionDialog.2605414502] +#. defaultMessage is: +#. Search by collection name, etc... +msgctxt "description" +msgid "Search by collection name, etc..." +msgstr "" + +#: build/locale/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.json +#. [src.discounts.components.DiscountCountrySelectDialog.2110418881] - search box placeholder +#. defaultMessage is: +#. Search by country name +msgctxt "search box placeholder" +msgid "Search by country name" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.json +#. [src.shipping.components.ShippingZoneCountriesAssignDialog.2110418881] +#. defaultMessage is: +#. Search by country name +msgctxt "description" +msgid "Search by country name" +msgstr "" + +#: build/locale/src/components/AssignProductDialog/AssignProductDialog.json +#. [src.components.AssignProductDialog.2336947364] +#. defaultMessage is: +#. Search by product name, attribute, product type etc... +#: build/locale/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.json +#. [src.orders.components.OrderProductAddDialog.2336947364] +#. defaultMessage is: +#. Search by product name, attribute, product type etc... +msgctxt "description" +msgid "Search by product name, attribute, product type etc..." +msgstr "" + +#: build/locale/src/components/SeoForm/SeoForm.json +#. [src.components.SeoForm.1991321627] +#. defaultMessage is: +#. Search engine description +msgctxt "description" +msgid "Search engine description" +msgstr "" + +#: build/locale/src/components/SeoForm/SeoForm.json +#. [src.components.SeoForm.1324250412] +#. defaultMessage is: +#. Search engine title +msgctxt "description" +msgid "Search engine title" +msgstr "" + +#: build/locale/src/attributes/components/AttributeList/AttributeList.json +#. [src.attributes.components.AttributeList.2235596452] - attribute can be searched in dashboard +#. defaultMessage is: +#. Searchable +msgctxt "attribute can be searched in dashboard" +msgid "Searchable" +msgstr "" + +#: build/locale/src/components/Filter/FilterContent.json +#. [src.components.Filter.2230339185] +#. defaultMessage is: +#. Select Filter... +#: build/locale/src/components/Filter/FilterElement.json +#. [src.components.Filter.2230339185] +#. defaultMessage is: +#. Select Filter... +msgctxt "description" +msgid "Select Filter..." +msgstr "" + +#: build/locale/src/products/components/ProductVariantImages/ProductVariantImages.json +#. [src.products.components.ProductVariantImages.3449133076] +#. defaultMessage is: +#. Select a specific variant image from product images +msgctxt "description" +msgid "Select a specific variant image from product images" +msgstr "" + +#: build/locale/src/orders/components/OrderListPage/OrderListPage.json +#. [src.orders.components.OrderListPage.3524904717] +#. defaultMessage is: +#. Select all orders where: +msgctxt "description" +msgid "Select all orders where:" +msgstr "" + +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.1421689426] +#. defaultMessage is: +#. Select all products where: +msgctxt "description" +msgid "Select all products where:" +msgstr "" + +#: build/locale/src/components/TableHead/TableHead.json +#. [src.components.TableHead.868570480] +#. defaultMessage is: +#. Selected {number} items +msgctxt "description" +msgid "Selected {number} items" +msgstr "" + +#: build/locale/src/products/components/ProductVariantPrice/ProductVariantPrice.json +#. [src.products.components.ProductVariantPrice.2238565650] +#. defaultMessage is: +#. Selling price override +msgctxt "description" +msgid "Selling price override" +msgstr "" + +#: build/locale/src/components/Timeline/Timeline.json +#. [src.components.Timeline.1359200231] - add order note, button +#. defaultMessage is: +#. Send +msgctxt "add order note, button" +msgid "Send" +msgstr "" + +#: build/locale/src/staff/components/StaffAddMemberDialog/StaffAddMemberDialog.json +#. [src.staff.components.StaffAddMemberDialog.449055697] - button +#. defaultMessage is: +#. Send invite +msgctxt "button" +msgid "Send invite" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddress/CustomerAddress.json +#. [src.customers.components.CustomerAddress.3096438859] - button +#. defaultMessage is: +#. Set as default billing address +msgctxt "button" +msgid "Set as default billing address" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddress/CustomerAddress.json +#. [src.customers.components.CustomerAddress.2131178753] - button +#. defaultMessage is: +#. Set as default shipping address +msgctxt "button" +msgid "Set as default shipping address" +msgstr "" + +#: build/locale/src/discounts/components/VoucherDates/VoucherDates.json +#. [src.discounts.components.VoucherDates.1596226028] - voucher end date, switch button +#. defaultMessage is: +#. Set end date +msgctxt "voucher end date, switch button" +msgid "Set end date" +msgstr "" + +#: build/locale/src/discounts/translations.json +#. [src.discounts.shipment] - voucher discount +#. defaultMessage is: +#. Shipment +msgctxt "voucher discount" +msgid "Shipment" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.1325966144] - order shipping method name +#. defaultMessage is: +#. Shipping +msgctxt "order shipping method name" +msgid "Shipping" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.json +#. [src.productTypes.components.ProductTypeShipping.1325966144] - product type shipping settings, section header +#. defaultMessage is: +#. Shipping +msgctxt "product type shipping settings, section header" +msgid "Shipping" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.json +#. [src.shipping.components.ShippingZoneDetailsPage.1325966144] +#. defaultMessage is: +#. Shipping +msgctxt "description" +msgid "Shipping" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.json +#. [src.shipping.components.ShippingZonesListPage.1325966144] - header +#. defaultMessage is: +#. Shipping +msgctxt "header" +msgid "Shipping" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.2758581442] +#. defaultMessage is: +#. Shipping Address +msgctxt "description" +msgid "Shipping Address" +msgstr "" + +#: build/locale/src/intl.json +#. [src.shipping] - shipping section name +#. defaultMessage is: +#. Shipping Methods +msgctxt "shipping section name" +msgid "Shipping Methods" +msgstr "" + +#: build/locale/src/shipping/components/ShippingWeightUnitForm/ShippingWeightUnitForm.json +#. [src.shipping.components.ShippingWeightUnitForm.549146363] +#. defaultMessage is: +#. Shipping Weight Unit +msgctxt "description" +msgid "Shipping Weight Unit" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.json +#. [src.shipping.components.ShippingZoneInfo.1109610983] +#. defaultMessage is: +#. Shipping Zone Name +msgctxt "description" +msgid "Shipping Zone Name" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddresses/CustomerAddresses.json +#. [src.customers.components.CustomerAddresses.3517722732] - subsection header +#. defaultMessage is: +#. Shipping address +msgctxt "subsection header" +msgid "Shipping address" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZonesList/ShippingZonesList.json +#. [src.shipping.components.ShippingZonesList.2942726079] - sort shipping methods by zone, section header +#. defaultMessage is: +#. Shipping by zone +msgctxt "sort shipping methods by zone, section header" +msgid "Shipping by zone" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.651019008] - order history message +#. defaultMessage is: +#. Shipping details was sent to customer +msgctxt "order history message" +msgid "Shipping details was sent to customer" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.2824936338] +#. defaultMessage is: +#. Shipping method provided, but no product requires it +msgctxt "description" +msgid "Shipping method provided, but no product requires it" +msgstr "" + +#: build/locale/src/orders/views/OrderDetails/OrderDetailsMessages.json +#. [src.orders.views.OrderDetails.617145655] +#. defaultMessage is: +#. Shipping method successfully updated +msgctxt "description" +msgid "Shipping method successfully updated" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.3453124210] - order history message +#. defaultMessage is: +#. Shipping tracking number was sent to customer +msgctxt "order history message" +msgid "Shipping tracking number was sent to customer" +msgstr "" + +#: build/locale/src/intl.json +#. [src.show] - button +#. defaultMessage is: +#. Show +msgctxt "button" +msgid "Show" +msgstr "" + +#: build/locale/src/taxes/components/TaxConfiguration/TaxConfiguration.json +#. [src.taxes.components.TaxConfiguration.2102582640] +#. defaultMessage is: +#. Show gross prices to customers in the storefront +msgctxt "description" +msgid "Show gross prices to customers in the storefront" +msgstr "" + +#: build/locale/src/products/components/ProductOrganization/ProductOrganization.json +#. [src.products.components.ProductOrganization.150865454] - product is not configurable +#. defaultMessage is: +#. Simple +msgctxt "product is not configurable" +msgid "Simple" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.1211157042] - product type +#. defaultMessage is: +#. Simple product +msgctxt "product type" +msgid "Simple product" +msgstr "" + +#: build/locale/src/intl.json +#. [src.siteSettings] - site settings section name +#. defaultMessage is: +#. Site Settings +msgctxt "site settings section name" +msgid "Site Settings" +msgstr "" + +#: build/locale/src/pages/components/PageList/PageList.json +#. [src.pages.components.PageList.3478065224] - page internal name +#. defaultMessage is: +#. Slug +#: build/locale/src/pages/components/PageSlug/PageSlug.json +#. [src.pages.components.PageSlug.3478065224] - page internal name +#. defaultMessage is: +#. Slug +msgctxt "page internal name" +msgid "Slug" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.json +#. [src.productTypes.components.ProductTypeAttributes.3478065224] - attribute internal name +#. defaultMessage is: +#. Slug +msgctxt "attribute internal name" +msgid "Slug" +msgstr "" + +#: build/locale/src/misc.json +#. [src.socialHousing] - tax rate +#. defaultMessage is: +#. Social housing +msgctxt "tax rate" +msgid "Social housing" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.2968256006] +#. defaultMessage is: +#. Some products require shipping, but no method provided +msgctxt "description" +msgid "Some products require shipping, but no method provided" +msgstr "" + +#: build/locale/src/mutations.json +#. [src.1395232177] - error message +#. defaultMessage is: +#. Something went wrong. {errorMessage} +#: build/locale/src/queries.json +#. [src.1395232177] - error message +#. defaultMessage is: +#. Something went wrong. {errorMessage} +msgctxt "error message" +msgid "Something went wrong. {errorMessage}" +msgstr "" + +#: build/locale/src/components/NotFoundPage/NotFoundPage.json +#. [src.components.NotFoundPage.4036415297] +#. defaultMessage is: +#. Something's missing +msgctxt "description" +msgid "Something's missing" +msgstr "" + +#: build/locale/src/components/NotFoundPage/NotFoundPage.json +#. [src.components.NotFoundPage.4205980614] +#. defaultMessage is: +#. Sorry, the page was not found +msgctxt "description" +msgid "Sorry, the page was not found" +msgstr "" + +#: build/locale/src/auth/components/LoginPage/LoginPage.json +#. [src.auth.components.LoginPage.3476994590] +#. defaultMessage is: +#. Sorry, your username and/or password are incorrect. Please try again. +msgctxt "description" +msgid "Sorry, your username and/or password are incorrect. Please try again." +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.789263812] +#. defaultMessage is: +#. Specific Date +msgctxt "description" +msgid "Specific Date" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.2844426531] +#. defaultMessage is: +#. Specific Price +msgctxt "description" +msgid "Specific Price" +msgstr "" + +#: build/locale/src/discounts/translations.json +#. [src.discounts.products] - voucher discount +#. defaultMessage is: +#. Specific products +msgctxt "voucher discount" +msgid "Specific products" +msgstr "" + +#: build/locale/src/staff/components/StaffProperties/StaffProperties.json +#. [src.staff.components.StaffProperties.2650522200] - section header +#. defaultMessage is: +#. Staff Member Information +msgctxt "section header" +msgid "Staff Member Information" +msgstr "" + +#: build/locale/src/intl.json +#. [src.staff] - staff section name +#. defaultMessage is: +#. Staff Members +msgctxt "staff section name" +msgid "Staff Members" +msgstr "" + +#: build/locale/src/misc.json +#. [src.standard] - tax rate +#. defaultMessage is: +#. Standard +msgctxt "tax rate" +msgid "Standard" +msgstr "" + +#: build/locale/src/intl.json +#. [src.startDate] +#. defaultMessage is: +#. Start Date +msgctxt "description" +msgid "Start Date" +msgstr "" + +#: build/locale/src/intl.json +#. [src.startHour] +#. defaultMessage is: +#. Start Hour +msgctxt "description" +msgid "Start Hour" +msgstr "" + +#: build/locale/src/navigation/components/MenuItemDialog/MenuItemDialog.json +#. [menuItemDialogLinkPlaceholder] +#. defaultMessage is: +#. Start typing to begin search... +msgctxt "description" +msgid "Start typing to begin search..." +msgstr "" + +#: build/locale/src/discounts/components/SaleList/SaleList.json +#. [src.discounts.components.SaleList.47059407] - sale start date +#. defaultMessage is: +#. Starts +msgctxt "sale start date" +msgid "Starts" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.47059407] - voucher is active from date +#. defaultMessage is: +#. Starts +msgctxt "voucher is active from date" +msgid "Starts" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.1756106276] - order status +#. defaultMessage is: +#. Status +msgctxt "order status" +msgid "Status" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.1756106276] - order fulfillment status +#. defaultMessage is: +#. Status +msgctxt "order fulfillment status" +msgid "Status" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1756106276] - product status +#. defaultMessage is: +#. Status +msgctxt "product status" +msgid "Status" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.1756106276] - product variant status +#. defaultMessage is: +#. Status +msgctxt "product variant status" +msgid "Status" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.3841616483] - product stock +#. defaultMessage is: +#. Stock +msgctxt "product stock" +msgid "Stock" +msgstr "" + +#: build/locale/src/products/components/ProductVariantStock/ProductVariantStock.json +#. [src.products.components.ProductVariantStock.3841616483] - product variant stock, section header +#. defaultMessage is: +#. Stock +msgctxt "product variant stock, section header" +msgid "Stock" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.3645081351] +#. defaultMessage is: +#. Stock quantity +msgctxt "description" +msgid "Stock quantity" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.json +#. [src.siteSettings.components.SiteSettingsDetails.1987367127] +#. defaultMessage is: +#. Store Description +msgctxt "description" +msgid "Store Description" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.json +#. [src.siteSettings.components.SiteSettingsDetails.529433178] +#. defaultMessage is: +#. Store description is shown on taskbar after your store name +msgctxt "description" +msgid "Store description is shown on taskbar after your store name" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.1150975268] - section header +#. defaultMessage is: +#. Store information +msgctxt "section header" +msgid "Store information" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.1877630205] - attribute properties regarding storefront +#. defaultMessage is: +#. Storefront Properties +msgctxt "attribute properties regarding storefront" +msgid "Storefront Properties" +msgstr "" + +#: build/locale/src/categories/components/CategoryList/CategoryList.json +#. [src.categories.components.CategoryList.2159874182] - number of subcategories +#. defaultMessage is: +#. Subcategories +msgctxt "number of subcategories" +msgid "Subcategories" +msgstr "" + +#: build/locale/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.json +#. [src.categories.components.CategoryUpdatePage.2159874182] - number of subcategories in category +#. defaultMessage is: +#. Subcategories +msgctxt "number of subcategories in category" +msgid "Subcategories" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.json +#. [src.orders.components.OrderDraftDetailsSummary.781550514] - subtotal price or an order +#. defaultMessage is: +#. Subtotal +msgctxt "subtotal price or an order" +msgid "Subtotal" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.781550514] - order subtotal price +#. defaultMessage is: +#. Subtotal +msgctxt "order subtotal price" +msgid "Subtotal" +msgstr "" + +#: build/locale/src/attributes/views/AttributeCreate/AttributeCreate.json +#. [src.attributes.views.AttributeCreate.11941964] +#. defaultMessage is: +#. Successfully created attribute +msgctxt "description" +msgid "Successfully created attribute" +msgstr "" + +#: build/locale/src/pages/views/PageCreate.json +#. [src.pages.views.2680158037] +#. defaultMessage is: +#. Successfully created new page +msgctxt "description" +msgid "Successfully created new page" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeCreate.json +#. [src.productTypes.views.3822478981] +#. defaultMessage is: +#. Successfully created product type +msgctxt "description" +msgid "Successfully created product type" +msgstr "" + +#: build/locale/src/discounts/views/SaleCreate.json +#. [src.discounts.views.3707049729] +#. defaultMessage is: +#. Successfully created sale +msgctxt "description" +msgid "Successfully created sale" +msgstr "" + +#: build/locale/src/discounts/views/VoucherCreate.json +#. [src.discounts.views.655651329] +#. defaultMessage is: +#. Successfully created voucher +msgctxt "description" +msgid "Successfully created voucher" +msgstr "" + +#: build/locale/src/intl.json +#. [src.summary] +#. defaultMessage is: +#. Summary +msgctxt "description" +msgid "Summary" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.1240292548] - tax rate for a product type +#. defaultMessage is: +#. Tax +msgctxt "tax rate for a product type" +msgid "Tax" +msgstr "" + +#: build/locale/src/taxes/components/CountryTaxesPage/CountryTaxesPage.json +#. [src.taxes.components.CountryTaxesPage.2022558114] +#. defaultMessage is: +#. Tax Rate +msgctxt "description" +msgid "Tax Rate" +msgstr "" + +#: build/locale/src/taxes/components/CountryTaxesPage/CountryTaxesPage.json +#. [src.taxes.components.CountryTaxesPage.2737618795] - header +#. defaultMessage is: +#. Tax Rates in {countryName} +msgctxt "header" +msgid "Tax Rates in {countryName}" +msgstr "" + +#: build/locale/src/intl.json +#. [src.taxes] - taxes section name +#. defaultMessage is: +#. Taxes +msgctxt "taxes section name" +msgid "Taxes" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.3955023266] +#. defaultMessage is: +#. Taxes +#: build/locale/src/productTypes/components/ProductTypeTaxes/ProductTypeTaxes.json +#. [productTypeTaxesInputLabel] +#. defaultMessage is: +#. Taxes +msgctxt "description" +msgid "Taxes" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeTaxes/ProductTypeTaxes.json +#. [productTypeTaxesHeader] - section header +#. defaultMessage is: +#. Taxes +msgctxt "section header" +msgid "Taxes" +msgstr "" + +#: build/locale/src/taxes/components/CountryListPage/CountryListPage.json +#. [src.taxes.components.CountryListPage.3955023266] - header +#. defaultMessage is: +#. Taxes +msgctxt "header" +msgid "Taxes" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.json +#. [src.orders.components.OrderDraftDetailsSummary.3202709354] +#. defaultMessage is: +#. Taxes (VAT included) +msgctxt "description" +msgid "Taxes (VAT included)" +msgstr "" + +#: build/locale/src/home/components/HomeScreen.json +#. [homeScreenDisclaimerText2] +#. defaultMessage is: +#. The GraphQL API is beta quality. It is not fully optimized and some mutations or queries may be missing. +msgctxt "description" +msgid "The GraphQL API is beta quality. It is not fully optimized and some mutations or queries may be missing." +msgstr "" + +#: build/locale/src/home/components/HomeScreen.json +#. [homeScreenDisclaimerText1] +#. defaultMessage is: +#. The new dashboard and the GraphQL API are preview-quality software. +msgctxt "description" +msgid "The new dashboard and the GraphQL API are preview-quality software." +msgstr "" + +#: build/locale/src/customers/components/CustomerCreateAddress/CustomerCreateAddress.json +#. [src.customers.components.CustomerCreateAddress.401345057] +#. defaultMessage is: +#. The primary address of this customer. +msgctxt "description" +msgid "The primary address of this customer." +msgstr "" + +#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json +#. [src.orders.components.OrderDraftFinalizeDialog.1472924390] +#. defaultMessage is: +#. There are missing or incorrect informations about this order: +msgctxt "description" +msgid "There are missing or incorrect informations about this order:" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.882649212] - shipping method has no value limits +#. defaultMessage is: +#. There are no value limits +msgctxt "shipping method has no value limits" +msgid "There are no value limits" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.json +#. [src.customers.components.CustomerAddressListPage.1484733755] +#. defaultMessage is: +#. There is no address to show for this customer +msgctxt "description" +msgid "There is no address to show for this customer" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.json +#. [src.customers.components.CustomerAddressListPage.1428369222] +#. defaultMessage is: +#. This customer doesn’t have any adresses added to his address book. You can add address using the button below. +msgctxt "description" +msgid "This customer doesn’t have any adresses added to his address book. You can add address using the button below." +msgstr "" + +#: build/locale/src/customers/components/CustomerAddresses/CustomerAddresses.json +#. [src.customers.components.CustomerAddresses.3870425261] +#. defaultMessage is: +#. This customer has no addresses yet +msgctxt "description" +msgid "This customer has no addresses yet" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.json +#. [src.shipping.components.ShippingZoneCreatePage.4270729636] +#. defaultMessage is: +#. This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones +#: build/locale/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.json +#. [src.shipping.components.ShippingZoneDetailsPage.4270729636] +#. defaultMessage is: +#. This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones +msgctxt "description" +msgid "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.2215090771] - shipping method, switch button +#. defaultMessage is: +#. This is free shipping +msgctxt "shipping method, switch button" +msgid "This is free shipping" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.4107478955] - attribute slug input field helper text +#. defaultMessage is: +#. This is used internally. Make sure you don’t use spaces +msgctxt "attribute slug input field helper text" +msgid "This is used internally. Make sure you don’t use spaces" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.3156701241] +#. defaultMessage is: +#. This product has no variants +msgctxt "description" +msgid "This product has no variants" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeDetailsPage/ProductTypeDetailsPage.json +#. [src.productTypes.components.ProductTypeDetailsPage.1756957616] - switch button +#. defaultMessage is: +#. This product type has variants +msgctxt "switch button" +msgid "This product type has variants" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.4226393146] +#. defaultMessage is: +#. This rate will apply to all orders of all prices +msgctxt "description" +msgid "This rate will apply to all orders of all prices" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1388947267] +#. defaultMessage is: +#. This rate will apply to all orders of all weights +msgctxt "description" +msgid "This rate will apply to all orders of all weights" +msgstr "" + +#: build/locale/src/shipping/components/ShippingWeightUnitForm/ShippingWeightUnitForm.json +#. [src.shipping.components.ShippingWeightUnitForm.2863708228] +#. defaultMessage is: +#. This unit will be used as default shipping weight +msgctxt "description" +msgid "This unit will be used as default shipping weight" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1486599614] +#. defaultMessage is: +#. This will be shown to customers at checkout +msgctxt "description" +msgid "This will be shown to customers at checkout" +msgstr "" + +#: build/locale/src/discounts/components/SalePricing/SalePricing.json +#. [src.discounts.components.SalePricing.2503204759] - time during which sale is active +#. defaultMessage is: +#. Time Frame +msgctxt "time during which sale is active" +msgid "Time Frame" +msgstr "" + +#: build/locale/src/pages/components/PageInfo/PageInfo.json +#. [src.pages.components.PageInfo.1124600214] - page title +#. defaultMessage is: +#. Title +msgctxt "page title" +msgid "Title" +msgstr "" + +#: build/locale/src/pages/components/PageList/PageList.json +#. [src.pages.components.PageList.1124600214] - dialog header +#. defaultMessage is: +#. Title +msgctxt "dialog header" +msgid "Title" +msgstr "" + +#: build/locale/src/home/components/HomeAnalyticsCard/HomeAnalyticsCard.json +#. [homeAnalyticsCardHeader] +#. defaultMessage is: +#. Today +msgctxt "description" +msgid "Today" +msgstr "" + +#: build/locale/src/home/components/HomeProductListCard/HomeProductListCard.json +#. [homeProductsListCardHeader] - header +#. defaultMessage is: +#. Top products +msgctxt "header" +msgid "Top products" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.878013594] - order total amount +#. defaultMessage is: +#. Total +msgctxt "order total amount" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.json +#. [src.orders.components.OrderDraftDetailsProducts.878013594] - total price of ordered products +#. defaultMessage is: +#. Total +msgctxt "total price of ordered products" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.json +#. [src.orders.components.OrderDraftDetailsSummary.878013594] - total price of an order +#. defaultMessage is: +#. Total +msgctxt "total price of an order" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderDraftList/OrderDraftList.json +#. [src.orders.components.OrderDraftList.878013594] - order draft total price +#. defaultMessage is: +#. Total +msgctxt "order draft total price" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.878013594] - order line total price +#. defaultMessage is: +#. Total +#: build/locale/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.json +#. [src.orders.components.OrderUnfulfilledItems.878013594] - order line total price +#. defaultMessage is: +#. Total +msgctxt "order line total price" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderList/OrderList.json +#. [src.orders.components.OrderList.878013594] - total order price +#. defaultMessage is: +#. Total +msgctxt "total order price" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.878013594] - order total price +#. defaultMessage is: +#. Total +msgctxt "order total price" +msgid "Total" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillment/OrderFulfillment.json +#. [src.orders.components.OrderFulfillment.3254150098] +#. defaultMessage is: +#. Tracking Number: {trackingNumber} +msgctxt "description" +msgid "Tracking Number: {trackingNumber}" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.json +#. [src.orders.components.OrderFulfillmentDialog.3252172269] - fulfillment group +#. defaultMessage is: +#. Tracking number +msgctxt "fulfillment group" +msgid "Tracking number" +msgstr "" + +#: build/locale/src/orders/components/OrderFulfillmentTrackingDialog/OrderFulfillmentTrackingDialog.json +#. [src.orders.components.OrderFulfillmentTrackingDialog.3252172269] +#. defaultMessage is: +#. Tracking number +msgctxt "description" +msgid "Tracking number" +msgstr "" + +#: build/locale/src/translations/components/TranslationFields/TranslationFields.json +#. [src.translations.components.TranslationFields.2481190613] - Translated Name +#. defaultMessage is: +#. Translation +msgctxt "Translated Name" +msgid "Translation" +msgstr "" + +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsLong.json +#. [src.translations.components.TranslationFields.2481190613] +#. defaultMessage is: +#. Translation +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsRich.json +#. [src.translations.components.TranslationFields.2481190613] +#. defaultMessage is: +#. Translation +#: build/locale/src/translations/components/TranslationFields/TranslationFieldsShort.json +#. [src.translations.components.TranslationFields.2481190613] +#. defaultMessage is: +#. Translation +msgctxt "description" +msgid "Translation" +msgstr "" + +#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json +#. [src.translations.components.TranslationsCategoriesPage.2043581404] +#. defaultMessage is: +#. Translation Category "{categoryNane}" - {languageCode} +msgctxt "description" +msgid "Translation Category \"{categoryNane}\" - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json +#. [src.translations.components.TranslationsCollectionsPage.3055443821] - header +#. defaultMessage is: +#. Translation Collection "{collectionName}" - {languageCode} +msgctxt "header" +msgid "Translation Collection \"{collectionName}\" - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.json +#. [src.translations.components.TranslationsPagesPage.2806429775] - header +#. defaultMessage is: +#. Translation Page "{pageName}" - {languageCode} +msgctxt "header" +msgid "Translation Page \"{pageName}\" - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.json +#. [src.translations.components.TranslationsProductsPage.2713974050] - header +#. defaultMessage is: +#. Translation Product "{productName}" - {languageCode} +msgctxt "header" +msgid "Translation Product \"{productName}\" - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.json +#. [src.translations.components.TranslationsProductTypesPage.1281101905] - header +#. defaultMessage is: +#. Translation Product Type "{productTypeName}" - {languageCode} +msgctxt "header" +msgid "Translation Product Type \"{productTypeName}\" - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsSalesPage/TranslationsSalesPage.json +#. [src.translations.components.TranslationsSalesPage.3731955064] - header +#. defaultMessage is: +#. Translation Sale "{saleName}" - {languageCode} +msgctxt "header" +msgid "Translation Sale \"{saleName}\" - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationsVouchersPage/TranslationsVouchersPage.json +#. [src.translations.components.TranslationsVouchersPage.2447510181] - header +#. defaultMessage is: +#. Translation Voucher "{voucherName}" - {languageCode} +msgctxt "header" +msgid "Translation Voucher \"{voucherName}\" - {languageCode}" +msgstr "" + +#: build/locale/src/intl.json +#. [src.translations] - translations section name +#. defaultMessage is: +#. Translations +msgctxt "translations section name" +msgid "Translations" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.2460580333] - header +#. defaultMessage is: +#. Translations to {language} +msgctxt "header" +msgid "Translations to {language}" +msgstr "" + +#: build/locale/src/categories/components/CategoryProducts/CategoryProducts.json +#. [src.categories.components.CategoryProducts.1952810469] - product type +#. defaultMessage is: +#. Type +#: build/locale/src/collections/components/CollectionProducts/CollectionProducts.json +#. [src.collections.components.CollectionProducts.1952810469] - product type +#. defaultMessage is: +#. Type +#: build/locale/src/products/components/ProductListPage/ProductListPage.json +#. [src.products.components.ProductListPage.1952810469] - product type +#. defaultMessage is: +#. Type +msgctxt "product type" +msgid "Type" +msgstr "" + +#: build/locale/src/components/ProductList/ProductList.json +#. [src.components.ProductList.1952810469] - product +#. defaultMessage is: +#. Type +msgctxt "product" +msgid "Type" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.1952810469] - product type is either simple or configurable +#. defaultMessage is: +#. Type +msgctxt "product type is either simple or configurable" +msgid "Type" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeList/ProductTypeList.json +#. [src.productTypes.components.ProductTypeList.2253986440] - product type name +#. defaultMessage is: +#. Type Name +msgctxt "product type name" +msgid "Type Name" +msgstr "" + +#: build/locale/src/pages/components/PageSlug/PageSlug.json +#. [src.pages.components.PageSlug.1324178587] +#. defaultMessage is: +#. URL +msgctxt "description" +msgid "URL" +msgstr "" + +#: build/locale/src/components/RichTextEditor/LinkSource.json +#. [src.components.RichTextEditor.2925475978] +#. defaultMessage is: +#. URL Linked +msgctxt "description" +msgid "URL Linked" +msgstr "" + +#: build/locale/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.json +#. [src.siteSettings.components.SiteSettingsDetails.3808773492] +#. defaultMessage is: +#. URL of your online store +msgctxt "description" +msgid "URL of your online store" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.870815507] - unassign product from collection, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign product from collection, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [saleDetailsUnassignCategory] - unassign category from sale, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign category from sale, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [saleDetailsUnassignCollection] - unassign collection from sale, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign collection from sale, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [saleDetailsUnassignProduct] - unassign product from sale, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign product from sale, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [voucherDetailsUnassignCategory] - unassign category from voucher, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign category from voucher, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [voucherDetailsUnassignCollection] - unassign collection from voucher, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign collection from voucher, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [voucherDetailsUnassignProduct] - unassign product from voucher, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign product from voucher, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/productTypes/views/ProductTypeUpdate/index.json +#. [src.productTypes.views.ProductTypeUpdate.870815507] - unassign attribute from product type, button +#. defaultMessage is: +#. Unassign +msgctxt "unassign attribute from product type, button" +msgid "Unassign" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributeUnassignDialog/ProductTypeAttributeUnassignDialog.json +#. [src.productTypes.components.ProductTypeAttributeUnassignDialog.404238501] - dialog header +#. defaultMessage is: +#. Unassign Attribute From Product Type +msgctxt "dialog header" +msgid "Unassign Attribute From Product Type" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.json +#. [src.productTypes.components.ProductTypeBulkAttributeUnassignDialog.766918870] - dialog header +#. defaultMessage is: +#. Unassign Attribute from Product Type +msgctxt "dialog header" +msgid "Unassign Attribute from Product Type" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.1827854264] - dialog header +#. defaultMessage is: +#. Unassign Categories From Sale +msgctxt "dialog header" +msgid "Unassign Categories From Sale" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.2669520431] - dialog header +#. defaultMessage is: +#. Unassign Categories From Voucher +msgctxt "dialog header" +msgid "Unassign Categories From Voucher" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.1952217501] - dialog header +#. defaultMessage is: +#. Unassign Collections From Sale +msgctxt "dialog header" +msgid "Unassign Collections From Sale" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.1402402714] - dialog header +#. defaultMessage is: +#. Unassign Collections From Voucher +msgctxt "dialog header" +msgid "Unassign Collections From Voucher" +msgstr "" + +#: build/locale/src/discounts/views/SaleDetails.json +#. [src.discounts.views.3395246518] - dialog header +#. defaultMessage is: +#. Unassign Products From Sale +msgctxt "dialog header" +msgid "Unassign Products From Sale" +msgstr "" + +#: build/locale/src/discounts/views/VoucherDetails.json +#. [src.discounts.views.2072403265] - dialog header +#. defaultMessage is: +#. Unassign Products From Voucher +msgctxt "dialog header" +msgid "Unassign Products From Voucher" +msgstr "" + +#: build/locale/src/collections/views/CollectionDetails.json +#. [src.collections.views.3791354625] - dialog title +#. defaultMessage is: +#. Unassign products from collection +msgctxt "dialog title" +msgid "Unassign products from collection" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.1033175132] - product variant status +#. defaultMessage is: +#. Unavailable +msgctxt "product variant status" +msgid "Unavailable" +msgstr "" + +#: build/locale/src/intl.json +#. [src.undo] - button +#. defaultMessage is: +#. Undo +msgctxt "button" +msgid "Undo" +msgstr "" + +#: build/locale/src/misc.json +#. [src.unfulfilled] - order status +#. defaultMessage is: +#. Unfulfilled +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.unfulfilled] - order status +#. defaultMessage is: +#. Unfulfilled +msgctxt "order status" +msgid "Unfulfilled" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.1751787272] - order fulfillment status +#. defaultMessage is: +#. Unfulfilled +msgctxt "order fulfillment status" +msgid "Unfulfilled" +msgstr "" + +#: build/locale/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.json +#. [src.orders.components.OrderUnfulfilledItems.2886647373] - section header +#. defaultMessage is: +#. Unfulfilled ({quantity}) +msgctxt "section header" +msgid "Unfulfilled ({quantity})" +msgstr "" + +#: build/locale/src/misc.json +#. [src.unpaid] - payment status +#. defaultMessage is: +#. Unpaid +msgctxt "payment status" +msgid "Unpaid" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.2237014112] - unpublish collections +#. defaultMessage is: +#. Unpublish +msgctxt "unpublish collections" +msgid "Unpublish" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.2237014112] - unpublish page, button +#. defaultMessage is: +#. Unpublish +msgctxt "unpublish page, button" +msgid "Unpublish" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.2237014112] - unpublish product, button +#. defaultMessage is: +#. Unpublish +msgctxt "unpublish product, button" +msgid "Unpublish" +msgstr "" + +#: build/locale/src/pages/views/PageList.json +#. [src.pages.views.158565417] - dialog header +#. defaultMessage is: +#. Unpublish Pages +msgctxt "dialog header" +msgid "Unpublish Pages" +msgstr "" + +#: build/locale/src/products/views/ProductList/ProductList.json +#. [src.products.views.ProductList.3362608461] - dialog header +#. defaultMessage is: +#. Unpublish Products +msgctxt "dialog header" +msgid "Unpublish Products" +msgstr "" + +#: build/locale/src/collections/views/CollectionList.json +#. [src.collections.views.2637364047] - dialog title +#. defaultMessage is: +#. Unpublish collections +msgctxt "dialog title" +msgid "Unpublish collections" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.1542600502] - button +#. defaultMessage is: +#. Update rate +msgctxt "button" +msgid "Update rate" +msgstr "" + +#: build/locale/src/orders/components/OrderHistory/OrderHistory.json +#. [src.orders.components.OrderHistory.4265697648] - order history message +#. defaultMessage is: +#. Updated fulfillment group's tracking number +msgctxt "order history message" +msgid "Updated fulfillment group's tracking number" +msgstr "" + +#: build/locale/src/components/FileUpload/FileUpload.json +#. [src.components.FileUpload.3050254265] - upload file, button +#. defaultMessage is: +#. Upload +msgctxt "upload file, button" +msgid "Upload" +msgstr "" + +#: build/locale/src/intl.json +#. [src.uploadImage] - button +#. defaultMessage is: +#. Upload image +msgctxt "button" +msgid "Upload image" +msgstr "" + +#: build/locale/src/discounts/components/VoucherLimits/VoucherLimits.json +#. [src.discounts.components.VoucherLimits.3751756157] - voucher usage limit, header +#. defaultMessage is: +#. Usage Limit +msgctxt "voucher usage limit, header" +msgid "Usage Limit" +msgstr "" + +#: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json +#. [src.discounts.components.VoucherSummary.3751756157] - voucher value requirement +#. defaultMessage is: +#. Usage Limit +msgctxt "voucher value requirement" +msgid "Usage Limit" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.714335445] - use attribute in filtering +#. defaultMessage is: +#. Use in Filtering +msgctxt "use attribute in filtering" +msgid "Use in Filtering" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.1564730914] - attribute is filterable in storefront +#. defaultMessage is: +#. Use in faceted navigation +msgctxt "attribute is filterable in storefront" +msgid "Use in faceted navigation" +msgstr "" + +#: build/locale/src/attributes/components/AttributeList/AttributeList.json +#. [src.attributes.components.AttributeList.2186555805] - attribute can be searched in storefront +#. defaultMessage is: +#. Use in faceted search +msgctxt "attribute can be searched in storefront" +msgid "Use in faceted search" +msgstr "" + +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.277989856] +#. defaultMessage is: +#. Use variants for products that come in a variety of versions for example different sizes or colors +msgctxt "description" +msgid "Use variants for products that come in a variety of versions for example different sizes or colors" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.json +#. [src.productTypes.components.ProductTypeShipping.2927891783] +#. defaultMessage is: +#. Used to calculate rates for shipping for products of this product type, when specific weight is not given +msgctxt "description" +msgid "Used to calculate rates for shipping for products of this product type, when specific weight is not given" +msgstr "" + +#: build/locale/src/customers/components/CustomerDetails/CustomerDetails.json +#. [src.customers.components.CustomerDetails.2968565128] - check to mark this account as active +#. defaultMessage is: +#. User account active +msgctxt "check to mark this account as active" +msgid "User account active" +msgstr "" + +#: build/locale/src/staff/components/StaffAddMemberDialog/StaffAddMemberDialog.json +#. [src.staff.components.StaffAddMemberDialog.1570990296] +#. defaultMessage is: +#. User has full access +msgctxt "description" +msgid "User has full access" +msgstr "" + +#: build/locale/src/staff/components/StaffPermissions/StaffPermissions.json +#. [src.staff.components.StaffPermissions.1848599267] - checkbox label +#. defaultMessage is: +#. User has full access to the store +msgctxt "checkbox label" +msgid "User has full access to the store" +msgstr "" + +#: build/locale/src/staff/components/StaffStatus/StaffStatus.json +#. [src.staff.components.StaffStatus.881953347] - checkbox label +#. defaultMessage is: +#. User is active +msgctxt "checkbox label" +msgid "User is active" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.3917820600] - voucher uses +#. defaultMessage is: +#. Uses +msgctxt "voucher uses" +msgid "Uses" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.1817306106] - vat included in order price +#. defaultMessage is: +#. VAT included +msgctxt "vat included in order price" +msgid "VAT included" +msgstr "" + +#: build/locale/src/discounts/components/SaleList/SaleList.json +#. [src.discounts.components.SaleList.1148029984] - sale value +#. defaultMessage is: +#. Value +#: build/locale/src/discounts/components/SaleSummary/SaleSummary.json +#. [src.discounts.components.SaleSummary.1148029984] - sale value +#. defaultMessage is: +#. Value +msgctxt "sale value" +msgid "Value" +msgstr "" + +#: build/locale/src/discounts/components/VoucherList/VoucherList.json +#. [src.discounts.components.VoucherList.1148029984] - voucher value +#. defaultMessage is: +#. Value +#: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json +#. [src.discounts.components.VoucherSummary.1148029984] - voucher value +#. defaultMessage is: +#. Value +msgctxt "voucher value" +msgid "Value" +msgstr "" + +#: build/locale/src/discounts/components/VoucherValue/VoucherValue.json +#. [src.discounts.components.VoucherValue.1148029984] - section header +#. defaultMessage is: +#. Value +msgctxt "section header" +msgid "Value" +msgstr "" + +#: build/locale/src/products/components/ProductAttributes/ProductAttributes.json +#. [src.products.components.ProductAttributes.1148029984] - attribute value +#. defaultMessage is: +#. Value +msgctxt "attribute value" +msgid "Value" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.1923873558] - shipping method price range +#. defaultMessage is: +#. Value Range +msgctxt "shipping method price range" +msgid "Value Range" +msgstr "" + +#: build/locale/src/attributes/components/AttributeDetails/AttributeDetails.json +#. [src.attributes.components.AttributeDetails.2592224946] - check to require attribute to have value +#. defaultMessage is: +#. Value Required +msgctxt "check to require attribute to have value" +msgid "Value Required" +msgstr "" + +#: build/locale/src/attributes/views/AttributeDetails/AttributeDetails.json +#. [src.attributes.views.AttributeDetails.423042761] - attribute value deleted +#. defaultMessage is: +#. Value deleted +msgctxt "attribute value deleted" +msgid "Value deleted" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.2533614652] - order price range +#. defaultMessage is: +#. Value range +msgctxt "order price range" +msgid "Value range" +msgstr "" + +#: build/locale/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.json +#. [src.translations.components.TranslationsProductTypesPage.1567737068] - attribute values +#. defaultMessage is: +#. Value {number} +msgctxt "attribute values" +msgid "Value {number}" +msgstr "" + +#: build/locale/src/products/components/ProductAttributes/ProductAttributes.json +#. [src.products.components.ProductAttributes.1207761269] - attribute values +#. defaultMessage is: +#. Values +msgctxt "attribute values" +msgid "Values" +msgstr "" + +#: build/locale/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.json +#. [src.translations.components.TranslationsProductTypesPage.3538502409] - header +#. defaultMessage is: +#. Variant Attribute ({attributeName}) +msgctxt "header" +msgid "Variant Attribute ({attributeName})" +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.json +#. [src.productTypes.components.ProductTypeAttributes.888493112] - section header +#. defaultMessage is: +#. Variant Attributes +msgctxt "section header" +msgid "Variant Attributes" +msgstr "" + +#: build/locale/src/products/views/ProductVariant.json +#. [src.products.views.2279302139] +#. defaultMessage is: +#. Variant removed +msgctxt "description" +msgid "Variant removed" +msgstr "" + +#: build/locale/src/products/components/ProductVariantNavigation/ProductVariantNavigation.json +#. [src.products.components.ProductVariantNavigation.2153006789] - section header +#. defaultMessage is: +#. Variants +#: build/locale/src/products/components/ProductVariants/ProductVariants.json +#. [src.products.components.ProductVariants.2153006789] - section header +#. defaultMessage is: +#. Variants +msgctxt "section header" +msgid "Variants" +msgstr "" + +#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json +#. [src.orders.components.OrderCustomer.2672803871] - link +#. defaultMessage is: +#. View Profile +msgctxt "link" +msgid "View Profile" +msgstr "" + +#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json +#. [src.customers.components.CustomerOrders.3029139173] - button +#. defaultMessage is: +#. View all orders +msgctxt "button" +msgid "View all orders" +msgstr "" + +#: build/locale/src/configuration/index.json +#. [configurationMenuSiteSettings] +#. defaultMessage is: +#. View and update your site settings +msgctxt "description" +msgid "View and update your site settings" +msgstr "" + +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.1459686496] - section header +#. defaultMessage is: +#. Visibility +msgctxt "section header" +msgid "Visibility" +msgstr "" + +#: build/locale/src/pages/components/PageList/PageList.json +#. [src.pages.components.PageList.1459686496] - page status +#. defaultMessage is: +#. Visibility +msgctxt "page status" +msgid "Visibility" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1459686496] - product visibility +#. defaultMessage is: +#. Visibility +msgctxt "product visibility" +msgid "Visibility" +msgstr "" + +#: build/locale/src/attributes/components/AttributeList/AttributeList.json +#. [src.attributes.components.AttributeList.643174786] - attribute is visible +#. defaultMessage is: +#. Visible +msgctxt "attribute is visible" +msgid "Visible" +msgstr "" + +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.643174786] +#. defaultMessage is: +#. Visible +msgctxt "description" +msgid "Visible" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.643174786] - product is visible +#. defaultMessage is: +#. Visible +msgctxt "product is visible" +msgid "Visible" +msgstr "" + +#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json +#. [src.attributes.components.AttributeProperties.3876764312] - attribute +#. defaultMessage is: +#. Visible on Product Page in Storefront +msgctxt "attribute" +msgid "Visible on Product Page in Storefront" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.2444197639] - void payment, button +#. defaultMessage is: +#. Void +msgctxt "void payment, button" +msgid "Void" +msgstr "" + +#: build/locale/src/orders/components/OrderPaymentVoidDialog/OrderPaymentVoidDialog.json +#. [src.orders.components.OrderPaymentVoidDialog.3089049828] - dialog header +#. defaultMessage is: +#. Void Payment +msgctxt "dialog header" +msgid "Void Payment" +msgstr "" + +#: build/locale/src/translations/components/TranslationsVouchersPage/TranslationsVouchersPage.json +#. [src.translations.components.TranslationsVouchersPage.2599922713] +#. defaultMessage is: +#. Voucher Name +msgctxt "description" +msgid "Voucher Name" +msgstr "" + +#: build/locale/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.json +#. [src.discounts.components.VoucherDetailsPage.2071139683] +#. defaultMessage is: +#. Voucher applies to all countries +msgctxt "description" +msgid "Voucher applies to all countries" +msgstr "" + +#: build/locale/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.json +#. [src.discounts.components.VoucherDetailsPage.2102960822] +#. defaultMessage is: +#. Voucher is limited to these countries +msgctxt "description" +msgid "Voucher is limited to these countries" +msgstr "" + +#: build/locale/src/intl.json +#. [src.vouchers] - vouchers section name +#. defaultMessage is: +#. Vouchers +msgctxt "vouchers section name" +msgid "Vouchers" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json +#. [src.translations.components.TranslationsEntitiesListPage.749185240] +#. defaultMessage is: +#. Vouchers +msgctxt "description" +msgid "Vouchers" +msgstr "" + +#: build/locale/src/misc.json +#. [src.water] - tax rate +#. defaultMessage is: +#. Water +msgctxt "tax rate" +msgid "Water" +msgstr "" + +#: build/locale/src/components/ErrorPage/ErrorPage.json +#. [src.components.ErrorPage.3182212440] +#. defaultMessage is: +#. We've encountered a problem... +msgctxt "description" +msgid "We've encountered a problem..." +msgstr "" + +#: build/locale/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.json +#. [src.productTypes.components.ProductTypeShipping.746695941] +#. defaultMessage is: +#. Weight +msgctxt "description" +msgid "Weight" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.383202459] - weight based shipping methods, section header +#. defaultMessage is: +#. Weight Based Rates +msgctxt "weight based shipping methods, section header" +msgid "Weight Based Rates" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRates/ShippingZoneRates.json +#. [src.shipping.components.ShippingZoneRates.2600677138] - shipping method weight range +#. defaultMessage is: +#. Weight Range +msgctxt "shipping method weight range" +msgid "Weight Range" +msgstr "" + +#: build/locale/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.json +#. [src.shipping.components.ShippingZoneRateDialog.2324036635] - order weight range +#. defaultMessage is: +#. Weight range +msgctxt "order weight range" +msgid "Weight range" +msgstr "" + +#: build/locale/src/intl.json +#. [src.yes] +#. defaultMessage is: +#. Yes +msgctxt "description" +msgid "Yes" +msgstr "" + +#: build/locale/src/components/AddressEdit/AddressEdit.json +#. [src.components.AddressEdit.2965971965] +#. defaultMessage is: +#. ZIP / Postal code +#: build/locale/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.json +#. [src.siteSettings.components.SiteSettingsAddress.2965971965] +#. defaultMessage is: +#. ZIP / Postal code +msgctxt "description" +msgid "ZIP / Postal code" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [orderPaymentVATDoesNotApply] - vat not included in order price +#. defaultMessage is: +#. does not apply +msgctxt "vat not included in order price" +msgid "does not apply" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [orderPaymentShippingDoesNotApply] - order does not require shipping +#. defaultMessage is: +#. does not apply +msgctxt "order does not require shipping" +msgid "does not apply" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.3477667254] +#. defaultMessage is: +#. equals +msgctxt "description" +msgid "equals" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.3477667254] - product price +#. defaultMessage is: +#. equals +msgctxt "product price" +msgid "equals" +msgstr "" + +#: build/locale/src/components/Filter/FilterElement.json +#. [src.components.Filter.2755325844] +#. defaultMessage is: +#. from +msgctxt "description" +msgid "from" +msgstr "" + +#: build/locale/src/components/MoneyRange/MoneyRange.json +#. [src.components.MoneyRange.3729849657] - money +#. defaultMessage is: +#. from {money} +msgctxt "money" +msgid "from {money}" +msgstr "" + +#: build/locale/src/components/WeightRange/WeightRange.json +#. [src.components.WeightRange.4256193688] - weight +#. defaultMessage is: +#. from {value} {unit} +msgctxt "weight" +msgid "from {value} {unit}" +msgstr "" + +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.1438173764] - date is set as +#. defaultMessage is: +#. is set as +msgctxt "date is set as" +msgid "is set as" +msgstr "" + +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1438173764] - product status is set as +#. defaultMessage is: +#. is set as +msgctxt "product status is set as" +msgid "is set as" +msgstr "" + +#: build/locale/src/staff/views/StaffDetails.json +#. [src.staff.views.2240444792] - dialog header +#. defaultMessage is: +#. remove Staff User +msgctxt "dialog header" +msgid "remove Staff User" +msgstr "" + +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.1815688500] +#. defaultMessage is: +#. since {date} +msgctxt "description" +msgid "since {date}" +msgstr "" + +#: build/locale/src/components/Filter/FilterElement.json +#. [src.components.Filter.152217691] +#. defaultMessage is: +#. to +msgctxt "description" +msgid "to" +msgstr "" + +#: build/locale/src/components/MoneyRange/MoneyRange.json +#. [src.components.MoneyRange.12301532] - money +#. defaultMessage is: +#. to {money} +msgctxt "money" +msgid "to {money}" +msgstr "" + +#: build/locale/src/components/WeightRange/WeightRange.json +#. [src.components.WeightRange.264731940] - weight +#. defaultMessage is: +#. to {value} {unit} +msgctxt "weight" +msgid "to {value} {unit}" +msgstr "" + +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.2001551496] +#. defaultMessage is: +#. will be visible from {date} +msgctxt "description" +msgid "will be visible from {date}" +msgstr "" + +#: build/locale/src/home/components/HomeProductListCard/HomeProductListCard.json +#. [homeProductListCardOrders] - number of ordered products +#. defaultMessage is: +#. {amount,plural,one{One ordered} other{{amount} Ordered}} +msgctxt "number of ordered products" +msgid "{amount,plural,one{One ordered} other{{amount} Ordered}}" +msgstr "" + +#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json +#. [homeNotificationTableOrders] +#. defaultMessage is: +#. {amount,plural,one{One order} other{{amount} Orders}} are ready to fulfill +msgctxt "description" +msgid "{amount,plural,one{One order} other{{amount} Orders}} are ready to fulfill" +msgstr "" + +#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json +#. [homeNotificationTablePayments] +#. defaultMessage is: +#. {amount,plural,one{One payment} other{{amount} Payments}} to capture +msgctxt "description" +msgid "{amount,plural,one{One payment} other{{amount} Payments}} to capture" +msgstr "" + +#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json +#. [homeNotificationTableProducts] +#. defaultMessage is: +#. {amount,plural,one{One product} other{{amount} Products}} out of stock +msgctxt "description" +msgid "{amount,plural,one{One product} other{{amount} Products}} out of stock" +msgstr "" + +#: build/locale/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.json +#. [src.translations.components.TranslationsEntitiesList.1136143456] - translation progress +#. defaultMessage is: +#. {current} of {max} +msgctxt "translation progress" +msgid "{current} of {max}" +msgstr "" + +#: build/locale/src/components/MoneyRange/MoneyRange.json +#. [src.components.MoneyRange.1316359951] - money +#. defaultMessage is: +#. {fromMoney} - {toMoney} +msgctxt "money" +msgid "{fromMoney} - {toMoney}" +msgstr "" + +#: build/locale/src/components/WeightRange/WeightRange.json +#. [src.components.WeightRange.2892071052] - weight +#. defaultMessage is: +#. {fromValue} {fromUnit} - {toValue} {toUnit} +msgctxt "weight" +msgid "{fromValue} {fromUnit} - {toValue} {toUnit}" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.json +#. [src.customers.components.CustomerAddressListPage.489918044] - customer details, header +#. defaultMessage is: +#. {fullName} Details +msgctxt "customer details, header" +msgid "{fullName} Details" +msgstr "" + +#: build/locale/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.json +#. [src.customers.components.CustomerAddressListPage.1090326769] - customer's address book, header +#. defaultMessage is: +#. {fullName}'s Address Book +msgctxt "customer's address book, header" +msgid "{fullName}'s Address Book" +msgstr "" + +#: build/locale/src/components/LanguageSwitch/LanguageSwitch.json +#. [src.components.LanguageSwitch.4150219184] - button +#. defaultMessage is: +#. {languageName} - {languageCode} +msgctxt "button" +msgid "{languageName} - {languageCode}" +msgstr "" + +#: build/locale/src/translations/components/TranslationFields/TranslationFields.json +#. [src.translations.components.TranslationFields.282734765] +#. defaultMessage is: +#. {numberOFields} Translations, {numberOfTranslatedFields} Completed +msgctxt "description" +msgid "{numberOFields} Translations, {numberOfTranslatedFields} Completed" +msgstr "" + +#: build/locale/src/components/SeoForm/SeoForm.json +#. [src.components.SeoForm.3877274856] - character limit +#. defaultMessage is: +#. {numberOfCharacters} of {maxCharacters} characters +msgctxt "character limit" +msgid "{numberOfCharacters} of {maxCharacters} characters" +msgstr "" + +#: build/locale/src/components/ColumnPicker/ColumnPickerContent.json +#. [src.components.ColumnPicker.2715399461] - pick columns to display +#. defaultMessage is: +#. {numberOfSelected} columns selected out of {numberOfTotal} +msgctxt "pick columns to display" +msgid "{numberOfSelected} columns selected out of {numberOfTotal}" +msgstr "" + +#: build/locale/src/products/components/ProductAttributes/ProductAttributes.json +#. [src.products.components.ProductAttributes.1071548120] - number of product attributes +#. defaultMessage is: +#. {number} Attributes +msgctxt "number of product attributes" +msgid "{number} Attributes" +msgstr "" + +#: build/locale/src/components/CountryList/CountryList.json +#. [src.components.CountryList.2460766407] - number of countries +#. defaultMessage is: +#. {number} Countries +msgctxt "number of countries" +msgid "{number} Countries" +msgstr "" + +#: build/locale/src/orders/components/OrderPayment/OrderPayment.json +#. [src.orders.components.OrderPayment.2183023165] - ordered products +#. defaultMessage is: +#. {quantity} items +msgctxt "ordered products" +msgid "{quantity} items" +msgstr "" + +#: build/locale/src/components/Weight/Weight.json +#. [src.components.Weight.2781622322] - weight +#. defaultMessage is: +#. {value} {unit} +msgctxt "weight" +msgid "{value} {unit}" +msgstr "" diff --git a/package-lock.json b/package-lock.json index cd0478754..8bf2228c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,6 +97,24 @@ "@apollographql/graphql-language-service-types": "^2.0.0" } }, + "@babel/cli": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.5.5.tgz", + "integrity": "sha512-UHI+7pHv/tk9g6WXQKYz+kmXTI77YtuY3vqC59KIqcoWEjsJJSG6rAxKaLsgj3LDyadsPrCB929gVOKM6Hui0w==", + "dev": true, + "requires": { + "chokidar": "^2.0.4", + "commander": "^2.8.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "mkdirp": "^0.5.1", + "output-file-sync": "^2.0.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + } + }, "@babel/code-frame": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", @@ -435,6 +453,16 @@ "@babel/plugin-syntax-json-strings": "^7.2.0" } }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.2.0.tgz", + "integrity": "sha512-DohMOGDrZiMKS7LthjUZNNcWl8TAf5BZDwZAH4wpm55FuJTHgfqPGdibg7rZDmont/8Yg0zA03IgT6XLeP+4sg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-numeric-separator": "^7.2.0" + } + }, "@babel/plugin-proposal-object-rest-spread": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz", @@ -520,6 +548,15 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.2.0.tgz", + "integrity": "sha512-DroeVNkO/BnGpL2R7+ZNZqW+E24aR/4YWxP3Qb15d6lPU8KDzF8HlIUIRCOJRn4X77/oyW4mJY+7FHfY82NLtQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", @@ -1225,6 +1262,11 @@ "tslib": "^1" } }, + "@formatjs/intl-relativetimeformat": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-2.6.3.tgz", + "integrity": "sha512-sb3PcbTSNQfnL4HM2XKedt8Oopf2EwaoxyjeMbgvje6x1zQuf1oTAidLHT65Dkox7hfSql8ZjpAqWqnHJsLN9w==" + }, "@heroku-cli/color": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/@heroku-cli/color/-/color-1.1.14.tgz", @@ -2820,11 +2862,10 @@ "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": { + "version": "2.2.30", + "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.30.tgz", + "integrity": "sha512-98fB+yo7imSD2F7PF7GIpELNgtLNgo5wjivu0W5V4jx+KVVJxo6p/qN4zdzSTBWy4/sN3pPyXwnhRSD28QX+ag==" }, "@types/istanbul-lib-coverage": { "version": "2.0.1", @@ -4827,6 +4868,42 @@ } } }, + "babel-plugin-react-intl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/babel-plugin-react-intl/-/babel-plugin-react-intl-4.1.12.tgz", + "integrity": "sha512-dCw7LjfDCS03ugW0Oz1XG8J/OgAnEDsKqcyfzlDb4JL6aLiYz87XvM9sIdbMAdPZXaHLhj9GyK8CueyMIm66NQ==", + "dev": true, + "requires": { + "@babel/core": "^7.4.5", + "@babel/helper-plugin-utils": "^7.0.0", + "@types/babel__core": "^7.1.2", + "fs-extra": "^8.0.1", + "intl-messageformat-parser": "^3.0.7" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "babel-plugin-react-intl-auto": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-intl-auto/-/babel-plugin-react-intl-auto-2.2.0.tgz", + "integrity": "sha512-L6IS4NQCr+uGw8yOJ+tBfm5R0UhrM2mZyhN+X7jCsnEhTcWopkWe7geLm7AzJC2SWFXnr7phwXlJbN4erwKRrA==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5", + "murmurhash3js": "^3.0.1" + } + }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", @@ -7126,9 +7203,10 @@ } }, "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "dev": true }, "core-js-compat": { "version": "3.2.0", @@ -8893,6 +8971,13 @@ "promise": "^7.1.1", "setimmediate": "^1.0.5", "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } } }, "figgy-pudding": { @@ -9284,6 +9369,12 @@ "universalify": "^0.1.0" } }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, "fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -9899,6 +9990,15 @@ "assert-plus": "^1.0.0" } }, + "gettext-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.1.0.tgz", + "integrity": "sha1-LFpmONiTk0ubVQN9CtgstwBLJnk=", + "dev": true, + "requires": { + "encoding": "^0.1.11" + } + }, "git-parse": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/git-parse/-/git-parse-1.0.3.tgz", @@ -10247,6 +10347,12 @@ } } }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -10809,21 +10915,6 @@ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", "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": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -11103,6 +11194,30 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" }, + "intl-format-cache": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/intl-format-cache/-/intl-format-cache-4.1.10.tgz", + "integrity": "sha512-7NqorxPNPuhbtwlXe71Dbjh9NlLvkoUymCI2AS/cyIsG7wYr27x9E/h4P16vftHwsTOjiDIjM/oGukddxgcz3A==" + }, + "intl-locales-supported": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/intl-locales-supported/-/intl-locales-supported-1.4.5.tgz", + "integrity": "sha512-D7oriM5x46rd7kNlSW0f9noIBegFr3ReIM6xlMpwH4lfIPD/zvBelPlCjR10IK16boGJG9lKccOvRAM8wzpbrA==" + }, + "intl-messageformat": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-6.1.5.tgz", + "integrity": "sha512-Ae/3PwnShCkDtnPvx9FLlBj1xiooa5NeeFZBizOQZZ/iaLt8IvgkPCdadkOF3f++FWDOBVtP5RszhMkJQKqmng==", + "requires": { + "intl-format-cache": "^4.1.10", + "intl-messageformat-parser": "^3.0.7" + } + }, + "intl-messageformat-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-3.0.7.tgz", + "integrity": "sha512-L16VbbV3NFaiZV65XwOIH9fBe52TS2EkOR0k8Y4ratsgTE7KPEbcUCUrz/iEQwJo7BcWY4ohkZbeYZRgAiPR1Q==" + }, "into-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", @@ -13800,6 +13915,12 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, + "murmurhash3js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/murmurhash3js/-/murmurhash3js-3.0.1.tgz", + "integrity": "sha1-Ppg+W0fCoG9DpxMXTn5DXKBEuZg=", + "dev": true + }, "mustache": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz", @@ -14100,6 +14221,41 @@ "integrity": "sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ==", "dev": true }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + } + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -14551,6 +14707,17 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "output-file-sync": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", + "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "is-plain-obj": "^1.1.0", + "mkdirp": "^0.5.1" + } + }, "p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", @@ -15110,6 +15277,16 @@ "ts-pnp": "^1.1.2" } }, + "po2json": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz", + "integrity": "sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=", + "dev": true, + "requires": { + "gettext-parser": "1.1.0", + "nomnom": "1.8.1" + } + }, "polished": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/polished/-/polished-3.4.1.tgz", @@ -16077,6 +16254,47 @@ "once": "^1.4.0" } }, + "react-intl": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-3.1.8.tgz", + "integrity": "sha512-kUQvTfDvMpgvwDldsmTy/XQPPgaSquh3+mL0iEspKkGqtAM9J9p25jNy8+cP0w/Y5LfWQFniUjlEdCDznoTZ/Q==", + "requires": { + "@formatjs/intl-relativetimeformat": "^2.6.3", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/invariant": "^2.2.30", + "@types/react": "^16.0.0", + "hoist-non-react-statics": "^3.3.0", + "intl-format-cache": "^4.1.10", + "intl-locales-supported": "^1.4.5", + "intl-messageformat": "^6.1.5", + "intl-messageformat-parser": "^3.0.7", + "invariant": "^2.1.1", + "react": "^16.3.0", + "shallow-equal": "^1.1.0" + } + }, + "react-intl-po": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-intl-po/-/react-intl-po-2.2.2.tgz", + "integrity": "sha512-BvW4gyohm4Ac0sSN6dBJB3+PeIjsns+IE9JqT/7NolBRGNc+fCKzWa5e1eZdhu9nY+7W1t0sWqhrt+LXgXb6Iw==", + "dev": true, + "requires": { + "chalk": "^2.3.2", + "commander": "^2.15.1", + "glob": "^7.1.2", + "mkdirp": "^0.5.1", + "po2json": "^0.4.5", + "ramda": "^0.25.0" + }, + "dependencies": { + "ramda": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", + "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==", + "dev": true + } + } + }, "react-is": { "version": "16.9.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", @@ -16848,9 +17066,9 @@ "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.0.tgz", + "integrity": "sha512-4Liqw7ccABzsWV5BzeZeGRSq7KWIgQYzOcmRDEwSX4WAawlQpcAFXZ1Kid72XYrjSnK5yxOS6Gez/iGusYE/Pw==", "dev": true, "requires": { "glob": "^7.1.3" @@ -17243,8 +17461,7 @@ "shallow-equal": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.0.tgz", - "integrity": "sha512-Z21pVxR4cXsfwpMKMhCEIO1PCi5sp7KEp+CmOpBQ+E8GpHwKOw2sEzk7sgblM3d/j4z4gakoWEoPcjK0VJQogA==", - "dev": true + "integrity": "sha512-Z21pVxR4cXsfwpMKMhCEIO1PCi5sp7KEp+CmOpBQ+E8GpHwKOw2sEzk7sgblM3d/j4z4gakoWEoPcjK0VJQogA==" }, "shallowequal": { "version": "1.1.0", @@ -18881,6 +19098,14 @@ "dev": true, "requires": { "core-js": "^1.0.0" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + } } }, "pify": { @@ -19022,6 +19247,14 @@ "dev": true, "requires": { "core-js": "^1.0.0" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + } } }, "dedent": { @@ -19375,19 +19608,6 @@ } } }, - "ts-loader": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.5.tgz", - "integrity": "sha512-XYsjfnRQCBum9AMRZpk2rTYSVpdZBpZK+kDh0TeT3kxmQNBDVIeUjdPjY5RZry4eIAb8XHc4gYSUiUWPYvzSRw==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", - "micromatch": "^3.1.4", - "semver": "^5.0.1" - } - }, "ts-node": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", @@ -19603,6 +19823,12 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", diff --git a/package.json b/package.json index 075fbf8bb..44d166876 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,6 @@ "fuzzaldrin": "^2.1.0", "graphql": "^14.4.2", "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", "jss": "^9.8.7", "keycode": "^2.2.0", @@ -56,6 +53,7 @@ "react-helmet": "^5.2.1", "react-infinite-scroller": "^1.2.4", "react-inlinesvg": "^0.8.4", + "react-intl": "^3.1.8", "react-jss": "^8.6.1", "react-moment": "^0.7.9", "react-router": "^5.0.1", @@ -70,12 +68,15 @@ "use-react-router": "^1.0.7" }, "devDependencies": { + "@babel/cli": "^7.5.5", "@babel/core": "^7.5.4", "@babel/plugin-proposal-class-properties": "^7.5.0", "@babel/plugin-proposal-decorators": "^7.4.4", + "@babel/plugin-proposal-numeric-separator": "^7.2.0", "@babel/plugin-proposal-object-rest-spread": "^7.5.4", "@babel/preset-env": "^7.5.4", "@babel/preset-react": "^7.0.0", + "@babel/preset-typescript": "^7.3.3", "@babel/runtime": "^7.5.4", "@storybook/addon-storyshots": "^5.1.9", "@storybook/react": "^5.1.9", @@ -84,7 +85,6 @@ "@types/draft-js": "^0.10.34", "@types/enzyme": "^3.10.2", "@types/fuzzaldrin": "^2.1.2", - "@types/i18next": "^8.4.6", "@types/jest": "^23.3.14", "@types/lodash-es": "^4.17.3", "@types/moment-timezone": "^0.5.12", @@ -104,7 +104,10 @@ "babel-core": "^7.0.0-bridge.0", "babel-jest": "^23.6.0", "babel-loader": "^8.0.6", + "babel-plugin-react-intl": "^4.1.12", + "babel-plugin-react-intl-auto": "^2.2.0", "codecov": "^3.5.0", + "core-js": "^3.2.1", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", "enzyme-to-json": "^3.3.5", @@ -114,11 +117,12 @@ "jest": "^24.8.0", "jest-file": "^1.0.0", "plop": "^2.4.0", + "react-intl-po": "^2.2.2", "react-test-renderer": "^16.8.6", "regenerator-runtime": "^0.11.1", + "rimraf": "^2.7.0", "testcafe": "^1.3.3", "ts-jest": "^23.10.5", - "ts-loader": "^5.4.5", "tsconfig-paths-webpack-plugin": "^3.2.0", "tslint": "^5.18.0", "tslint-config-prettier": "^1.18.0", @@ -130,30 +134,9 @@ "optionalDependencies": { "fsevents": "^1.2.9" }, - "babel": { - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], - "plugins": [ - "@babel/plugin-proposal-class-properties", - [ - "@babel/plugin-proposal-decorators", - { - "decoratorsBeforeExport": true - } - ], - "@babel/plugin-proposal-object-rest-spread" - ] - }, "jest": { - "globals": { - "ts-jest": { - "tsConfig": "tsconfig.json" - } - }, "transform": { - "^.+\\.tsx?$": "ts-jest", + "^.+\\.(jsx?|tsx?)$": "babel-jest", "^.+\\.(png|svg|jpe?g)$": "jest-file" }, "testRegex": ".*\\.test\\.tsx?$", @@ -173,11 +156,15 @@ }, "scripts": { "build": "webpack -p", + "extract-json-messages": "rimraf build/locale && babel src 'src/**/*.{ts,tsx}' -o build/dashboard.bundle.js", + "extract-pot-messages": "rip json2pot \"build/locale/**/*.json\" -c description -o locale/messages.pot", + "extract-messages": "npm run extract-json-messages && npm run extract-pot-messages", + "build-messages": "rip po2json 'locale/**/*.po' -m 'build/locale/**/*.json' -o 'locale' -c 'description'", "build-types": "apollo client:codegen --target=typescript types --globalTypesFile=src/types/globalTypes.ts", "generate-component": "plop --plopfile .plop/plopfile.js", "lint": "tslint 'src/**/*.{ts,tsx}'", "lint-fix": "tslint 'src/**/*.{ts,tsx}' --fix", - "start": "webpack-dev-server --open", + "start": "webpack-dev-server --open -d", "storybook": "start-storybook -p 3000 -c src/storybook/", "build-storybook": "build-storybook -c src/storybook/ -o build/storybook", "test": "jest src/", diff --git a/react-intl.d.ts b/react-intl.d.ts new file mode 100644 index 000000000..efafa921d --- /dev/null +++ b/react-intl.d.ts @@ -0,0 +1,54 @@ +declare module "react-intl" { + import * as ReactIntl from "node_modules/react-intl"; + export * from "node_modules/react-intl"; + + export interface MessageDescriptor { + description?: string; + defaultMessage: string; + id?: string; + } + type Messages = Record< + Names, + MessageDescriptor + >; + type PrimitiveType = string | number | boolean | null | undefined | Date; + type FormatXMLElementFn = (...args: any[]) => string | object; + export interface IntlFormatters + extends Omit { + formatMessage( + descriptor: MessageDescriptor, + values?: Record + ): string; + formatMessage( + descriptor: MessageDescriptor, + values?: Record< + string, + PrimitiveType | React.ReactElement | FormatXMLElementFn + > + ): string | React.ReactNodeArray; + } + export interface FormattedMessageProps< + V extends Record = Record + > extends MessageDescriptor { + values?: V; + tagName?: React.ElementType; + children?(...nodes: React.ReactNodeArray): React.ReactNode; + } + + export function defineMessages( + messageDescriptors: Messages + ): Messages; + + export interface IntlShape extends ReactIntl.IntlConfig, IntlFormatters { + formatters: ReactIntl.Formatters; + } + + export class FormattedMessage< + TValues extends Record = Record< + string, + PrimitiveType | React.ReactElement | FormatXMLElementFn + > + > extends React.Component> {} + + export function useIntl(): IntlShape; +} diff --git a/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.tsx b/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.tsx index bd40e2c51..747b5f3df 100644 --- a/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.tsx +++ b/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.tsx @@ -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,36 @@ export interface AttributeBulkDeleteDialogProps { const AttributeBulkDeleteDialog: React.StatelessComponent< AttributeBulkDeleteDialogProps -> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => ( - - {{ quantity }} attributes?", - { - quantity - } - ) - }} - /> - -); +> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => { + const intl = useIntl(); + + return ( + + + {quantity} + }} + /> + + + ); +}; AttributeBulkDeleteDialog.displayName = "AttributeBulkDeleteDialog"; export default AttributeBulkDeleteDialog; diff --git a/src/attributes/components/AttributeDeleteDialog/AttributeDeleteDialog.tsx b/src/attributes/components/AttributeDeleteDialog/AttributeDeleteDialog.tsx index b6e577d88..90c3c09e3 100644 --- a/src/attributes/components/AttributeDeleteDialog/AttributeDeleteDialog.tsx +++ b/src/attributes/components/AttributeDeleteDialog/AttributeDeleteDialog.tsx @@ -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,33 @@ const AttributeDeleteDialog: React.FC = ({ onClose, onConfirm, open -}) => ( - - {{ name }}?", - { - name - } - ) - }} - /> - -); +}) => { + const intl = useIntl(); + + return ( + + + {name} + }} + /> + + + ); +}; AttributeDeleteDialog.displayName = "AttributeDeleteDialog"; export default AttributeDeleteDialog; diff --git a/src/attributes/components/AttributeDetails/AttributeDetails.tsx b/src/attributes/components/AttributeDetails/AttributeDetails.tsx index 038f0fa65..3e31b3e2d 100644 --- a/src/attributes/components/AttributeDetails/AttributeDetails.tsx +++ b/src/attributes/components/AttributeDetails/AttributeDetails.tsx @@ -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 { 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,78 +22,99 @@ export interface AttributeDetailsProps { onChange: (event: React.ChangeEvent) => void; } -const inputTypeChoices = [ - { - label: i18n.t("Dropdown"), - value: AttributeInputTypeEnum.DROPDOWN - }, - { - label: i18n.t("Multiple Select"), - value: AttributeInputTypeEnum.MULTISELECT - } -]; - const AttributeDetails: React.FC = ({ canChangeType, data, disabled, errors, onChange -}) => ( - - - - { + const intl = useIntl(); + const inputTypeChoices = [ + { + label: intl.formatMessage({ + defaultMessage: "Dropdown", + description: "product attribute type" + }), + value: AttributeInputTypeEnum.DROPDOWN + }, + { + label: intl.formatMessage({ + defaultMessage: "Multiple Select", + description: "product attribute type" + }), + value: AttributeInputTypeEnum.MULTISELECT + } + ]; + + return ( + + - - - - - - - - -); + + + + + + + + + + + ); +}; AttributeDetails.displayName = "AttributeDetails"; export default AttributeDetails; diff --git a/src/attributes/components/AttributeList/AttributeList.tsx b/src/attributes/components/AttributeList/AttributeList.tsx index 95dfc7cc4..d3edbcf6e 100644 --- a/src/attributes/components/AttributeList/AttributeList.tsx +++ b/src/attributes/components/AttributeList/AttributeList.tsx @@ -6,15 +6,15 @@ 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, useIntl } 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 { translateBoolean } from "@saleor/intl"; import { renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; -import { translateBoolean } from "@saleor/utils/i18n"; import { AttributeList_attributes_edges_node } from "../../types/AttributeList"; export interface AttributeListProps extends ListProps, ListActions { @@ -71,6 +71,7 @@ const AttributeList: React.StatelessComponent = ({ toolbar }) => { const classes = useStyles({}); + const intl = useIntl(); return ( @@ -83,23 +84,31 @@ const AttributeList: React.StatelessComponent = ({ toolbar={toolbar} > - {i18n.t("Attribute Code", { context: "attribute slug" })} + - {i18n.t("Default Label", { context: "attribute name" })} + - {i18n.t("Visible", { context: "attribute visibility" })} + - {i18n.t("Searchable", { - context: "attribute can be searched in dashboard" - })} + - {i18n.t("Use in faceted search", { - context: "attribute can be searched in storefront" - })} + @@ -145,21 +154,21 @@ const AttributeList: React.StatelessComponent = ({ {attribute ? ( - translateBoolean(attribute.visibleInStorefront) + translateBoolean(attribute.visibleInStorefront, intl) ) : ( )} {attribute ? ( - translateBoolean(attribute.filterableInDashboard) + translateBoolean(attribute.filterableInDashboard, intl) ) : ( )} {attribute ? ( - translateBoolean(attribute.filterableInStorefront) + translateBoolean(attribute.filterableInStorefront, intl) ) : ( )} @@ -170,7 +179,7 @@ const AttributeList: React.StatelessComponent = ({ () => ( - {i18n.t("No attributes found")} + ) diff --git a/src/attributes/components/AttributeListPage/AttributeListPage.tsx b/src/attributes/components/AttributeListPage/AttributeListPage.tsx index 4daa73528..b219d160a 100644 --- a/src/attributes/components/AttributeListPage/AttributeListPage.tsx +++ b/src/attributes/components/AttributeListPage/AttributeListPage.tsx @@ -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,17 +18,25 @@ export interface AttributeListPageProps extends PageListProps, ListActions { const AttributeListPage: React.FC = ({ onAdd, ...listProps -}) => ( - - - - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + + + ); +}; AttributeListPage.displayName = "AttributeListPage"; export default AttributeListPage; diff --git a/src/attributes/components/AttributePage/AttributePage.tsx b/src/attributes/components/AttributePage/AttributePage.tsx index 209397676..1b90fe960 100644 --- a/src/attributes/components/AttributePage/AttributePage.tsx +++ b/src/attributes/components/AttributePage/AttributePage.tsx @@ -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 = ({ onValueReorder, onValueUpdate }) => { + const intl = useIntl(); const initialForm: AttributePageFormData = attribute === null ? { @@ -109,12 +111,15 @@ const AttributePage: React.FC = ({
{({ change, errors: formErrors, data, submit }) => ( - {i18n.t("Attributes")} + + {intl.formatMessage(sectionNames.attributes)} + attribute.name) } diff --git a/src/attributes/components/AttributeProperties/AttributeProperties.tsx b/src/attributes/components/AttributeProperties/AttributeProperties.tsx index e61df33be..4521d4c76 100644 --- a/src/attributes/components/AttributeProperties/AttributeProperties.tsx +++ b/src/attributes/components/AttributeProperties/AttributeProperties.tsx @@ -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,103 +26,130 @@ const AttributeProperties: React.FC = ({ errors, disabled, onChange -}) => ( - - - - {/* - {i18n.t("General Properties")} - -
- - - {i18n.t("Variant Attribute")} - - {i18n.t( - "If enabled, you'll be able to use this attribute to create product variants" - )} - - - } - onChange={onChange} - /> */} +}) => { + const intl = useIntl(); - - {i18n.t("Storefront Properties")} - -
- - {data.filterableInStorefront && ( - + + + {/* + + +
+ + + + + + + + } + onChange={onChange} + /> */} + + + + +
+ - )} - - - - - - {i18n.t("Dashboard Properties")} - -
- - - {i18n.t( - "If enabled, you’ll be able to use this attribute to filter products in product list." - )} - - } - onChange={onChange} - /> - - - {i18n.t( - "If enable this attribute can be used as a column in product table." - )} - - } - onChange={onChange} - /> -
-
-); + {data.filterableInStorefront && ( + + )} + + + + + + +
+ + + + + } + onChange={onChange} + /> + + + + + } + onChange={onChange} + /> + + + ); +}; AttributeProperties.displayName = "AttributeProperties"; export default AttributeProperties; diff --git a/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.tsx b/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.tsx index 3edd078ee..032ddbf40 100644 --- a/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.tsx +++ b/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.tsx @@ -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,43 @@ const AttributeValueDeleteDialog: React.FC = ({ onClose, onConfirm, open -}) => ( - - - {useName - ? i18n.t( - 'Are you sure you want to remove "{{ name }}" value? If you remove it you won’t be able to assign it to any of the products with "{{ attributeName }}" attribute.', - { +}) => { + const intl = useIntl(); + + return ( + + + {useName ? ( + - -); + }} + /> + ) : ( + + )} + + + ); +}; AttributeValueDeleteDialog.displayName = "AttributeValueDeleteDialog"; export default AttributeValueDeleteDialog; diff --git a/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.tsx b/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.tsx index 7bb83ca00..c54150edd 100644 --- a/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.tsx +++ b/src/attributes/components/AttributeValueEditDialog/AttributeValueEditDialog.tsx @@ -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 { buttonMessages } 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,17 @@ const AttributeValueEditDialog: React.StatelessComponent< return ( - {attributeValue === null - ? i18n.t("Add Value", { - context: "add attribute value" - }) - : i18n.t("Edit Value", { - context: "edit attribute value" - })} + {attributeValue === null ? ( + + ) : ( + + )} {({ change, data, errors: formErrors, submit }) => ( @@ -67,8 +73,9 @@ 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" })} value={data.name} onChange={change} @@ -76,7 +83,7 @@ const AttributeValueEditDialog: React.StatelessComponent< - {i18n.t("Save")} + diff --git a/src/attributes/components/AttributeValues/AttributeValues.tsx b/src/attributes/components/AttributeValues/AttributeValues.tsx index 4d6f3c444..bd9d2fbf3 100644 --- a/src/attributes/components/AttributeValues/AttributeValues.tsx +++ b/src/attributes/components/AttributeValues/AttributeValues.tsx @@ -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,21 @@ const AttributeValues: React.FC = ({ values }) => { const classes = useStyles({}); + const intl = useIntl(); return ( - {i18n.t("Add value", { context: "button" })} + } /> @@ -79,10 +86,16 @@ const AttributeValues: React.FC = ({ - {i18n.t("Admin")} + - {i18n.t("Default Store View")} + @@ -116,7 +129,12 @@ const AttributeValues: React.FC = ({ ), () => ( - {i18n.t("No values found")} + + + ) )} diff --git a/src/attributes/index.tsx b/src/attributes/index.tsx index b98ce72ab..a21d82435 100644 --- a/src/attributes/index.tsx +++ b/src/attributes/index.tsx @@ -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,14 +43,18 @@ const AttributeDetails: React.FC> = ({ ); }; -export const AttributeSection: React.FC = () => ( - <> - - - - - - - -); +export const AttributeSection: React.FC = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + ); +}; export default AttributeSection; diff --git a/src/attributes/views/AttributeCreate/AttributeCreate.tsx b/src/attributes/views/AttributeCreate/AttributeCreate.tsx index eac1dad27..4a7f87aae 100644 --- a/src/attributes/views/AttributeCreate/AttributeCreate.tsx +++ b/src/attributes/views/AttributeCreate/AttributeCreate.tsx @@ -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 = ({ params }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const [values, setValues] = React.useState< AttributeValueEditDialogFormData[] @@ -75,7 +76,11 @@ const AttributeDetails: React.FC = ({ 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" + }) + }); navigate(attributeUrl(data.attributeCreate.attribute.id)); } }; @@ -84,10 +89,15 @@ const AttributeDetails: React.FC = ({ params }) => { setValueErrors([ { field: "name", - message: i18n.t("A value named {{ name }} already exists", { - context: "value edit error", - name: input.name - }) + message: intl.formatMessage( + { + defaultMessage: "A value named { name } already exists", + description: "attribute value edit error" + }, + { + name: input.name + } + ) } ]); } else { @@ -100,10 +110,15 @@ const AttributeDetails: React.FC = ({ params }) => { setValueErrors([ { field: "name", - message: i18n.t("A value named {{ name }} already exists", { - context: "value edit error", - name: input.name - }) + message: intl.formatMessage( + { + defaultMessage: "A value named { name } already exists", + description: "attribute value edit error" + }, + { + name: input.name + } + ) } ]); } else { diff --git a/src/attributes/views/AttributeDetails/AttributeDetails.tsx b/src/attributes/views/AttributeDetails/AttributeDetails.tsx index c5a04e2ff..e6870487a 100644 --- a/src/attributes/views/AttributeDetails/AttributeDetails.tsx +++ b/src/attributes/views/AttributeDetails/AttributeDetails.tsx @@ -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 = ({ id, params }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const closeModal = () => navigate( @@ -63,39 +65,51 @@ const AttributeDetails: React.FC = ({ id, params }) => { const handleDelete = (data: AttributeDelete) => { if (data.attributeDelete.errors.length === 0) { - notify({ text: i18n.t("Attribute removed") }); + notify({ + text: intl.formatMessage({ + defaultMessage: "Attribute deleted" + }) + }); navigate(attributeListUrl()); } }; const handleValueDelete = (data: AttributeValueDelete) => { if (data.attributeValueDelete.errors.length === 0) { - notify({ text: i18n.t("Value removed") }); + notify({ + text: intl.formatMessage({ + defaultMessage: "Value deleted", + description: "attribute value deleted" + }) + }); 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" + }) + }); 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 }); } }; diff --git a/src/attributes/views/AttributeList/AttributeList.tsx b/src/attributes/views/AttributeList/AttributeList.tsx index 6e311cfab..262d4e727 100644 --- a/src/attributes/views/AttributeList/AttributeList.tsx +++ b/src/attributes/views/AttributeList/AttributeList.tsx @@ -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 = ({ params }) => { const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); + const intl = useIntl(); const closeModal = () => navigate( @@ -71,7 +72,10 @@ const AttributeList: React.FC = ({ params }) => { if (data.attributeBulkDelete.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Attributes removed") + text: intl.formatMessage({ + defaultMessage: "Attributes successfully delete", + description: "deleted multiple attributes" + }) }); reset(); refetch(); @@ -116,12 +120,15 @@ const AttributeList: React.FC = ({ params }) => { /> params.ids.length > 0) + } onConfirm={() => attributeBulkDelete({ variables: { ids: params.ids } }) } onClose={closeModal} - quantity={maybe(() => params.ids.length.toString(), "...")} + quantity={maybe(() => params.ids.length)} /> ); diff --git a/src/auth/components/LoginPage/LoginPage.tsx b/src/auth/components/LoginPage/LoginPage.tsx index 644f59fa2..c361257d1 100644 --- a/src/auth/components/LoginPage/LoginPage.tsx +++ b/src/auth/components/LoginPage/LoginPage.tsx @@ -9,6 +9,7 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import React from "react"; import SVG from "react-inlinesvg"; +import { FormattedMessage, useIntl } from "react-intl"; import backgroundArt from "@assets/images/login-background.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 { FormSpacer } from "@saleor/components/FormSpacer"; import useTheme from "@saleor/hooks/useTheme"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; export interface FormData { email: string; @@ -117,6 +118,7 @@ export interface LoginCardProps extends WithStyles { const LoginCard = withStyles(styles, { name: "LoginCard" })( ({ classes, error, disableLoginButton, onSubmit }: LoginCardProps) => { const { isDark } = useTheme(); + const intl = useIntl(); return ( {error && (
- Please try again." - ) - }} - /> + + +
)} @@ -187,7 +189,10 @@ const LoginCard = withStyles(styles, { name: "LoginCard" })( type="submit" data-tc="submit" > - {i18n.t("Login")} + {/* diff --git a/src/categories/components/CategoryBackground/CategoryBackground.tsx b/src/categories/components/CategoryBackground/CategoryBackground.tsx index 2dca98b19..2c5d9925e 100644 --- a/src/categories/components/CategoryBackground/CategoryBackground.tsx +++ b/src/categories/components/CategoryBackground/CategoryBackground.tsx @@ -1,10 +1,6 @@ -import { - createStyles, - Theme, - withStyles, - WithStyles -} from "@material-ui/core/styles"; +import { Theme } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; +import makeStyles from "@material-ui/styles/makeStyles"; import React from "react"; import Button from "@material-ui/core/Button"; @@ -15,35 +11,35 @@ import Hr from "@saleor/components/Hr"; import ImageTile from "@saleor/components/ImageTile"; import ImageUpload from "@saleor/components/ImageUpload"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; +import { FormattedMessage, useIntl } from "react-intl"; import { CategoryDetails_category_backgroundImage } from "../../types/CategoryDetails"; import { FormData } from "../CategoryUpdatePage"; -const styles = (theme: Theme) => - createStyles({ - fileField: { - display: "none" - }, - image: { - height: "100%", - objectFit: "contain", - userSelect: "none", - width: "100%" - }, - imageContainer: { - background: "#ffffff", - border: "1px solid #eaeaea", - borderRadius: theme.spacing.unit, - height: 148, - justifySelf: "start", - overflow: "hidden", - padding: theme.spacing.unit * 2, - position: "relative", - width: 148 - } - }); +const useStyles = makeStyles((theme: Theme) => ({ + fileField: { + display: "none" + }, + image: { + height: "100%", + objectFit: "contain", + userSelect: "none", + width: "100%" + }, + imageContainer: { + background: "#ffffff", + border: "1px solid #eaeaea", + borderRadius: theme.spacing.unit, + height: 148, + justifySelf: "start", + overflow: "hidden", + padding: theme.spacing.unit * 2, + position: "relative", + width: 148 + } +})); -export interface CategoryBackgroundProps extends WithStyles { +export interface CategoryBackgroundProps { data: FormData; image: CategoryDetails_category_backgroundImage; onChange: (event: React.ChangeEvent) => void; @@ -51,83 +47,78 @@ export interface CategoryBackgroundProps extends WithStyles { onImageUpload: (file: File) => void; } -export const CategoryBackground = withStyles(styles)( - class CategoryBackgroundComponent extends React.Component< - CategoryBackgroundProps, - {} - > { - imgInputAnchor = React.createRef(); +const CategoryBackground: React.FC = props => { + const classes = useStyles(props); + const intl = useIntl(); + const anchor = React.useRef(); - clickImgInput = () => this.imgInputAnchor.current.click(); + const { data, onImageUpload, image, onChange, onImageDelete } = props; - render() { - const { - classes, - data, - onImageUpload, - image, - onChange, - onImageDelete - } = this.props; - return ( - - - - onImageUpload(event.target.files[0])} - type="file" - ref={this.imgInputAnchor} - /> - - } - /> - {image === undefined ? ( - -
-
- -
-
-
- ) : image === null ? ( - - ) : ( - - - - )} + const handleImageUploadButtonClick = () => anchor.current.click(); - {image && ( - <> -
- - - - - )} -
- ); - } - } -); + return ( + + + + onImageUpload(event.target.files[0])} + type="file" + ref={anchor} + /> + + } + /> + {image === undefined ? ( + +
+
+ +
+
+
+ ) : image === null ? ( + + ) : ( + + + + )} + + {image && ( + <> +
+ + + + + )} +
+ ); +}; CategoryBackground.displayName = "CategoryBackground"; export default CategoryBackground; diff --git a/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx b/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx index 664d3b2b5..3e095189c 100644 --- a/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx +++ b/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx @@ -1,5 +1,6 @@ import { ContentState, convertToRaw, RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; @@ -9,7 +10,7 @@ import Form from "@saleor/components/Form"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { UserError } from "../../../types"; import CategoryDetailsForm from "../../components/CategoryDetailsForm"; @@ -43,50 +44,58 @@ export const CategoryCreatePage: React.StatelessComponent< onBack, errors: userErrors, saveButtonBarState -}) => ( - - {({ data, change, errors, submit, hasChanged }) => ( - - {i18n.t("Categories")} - -
- { + const intl = useIntl(); + return ( + + {({ data, change, errors, submit, hasChanged }) => ( + + + {intl.formatMessage(sectionNames.categories)} + + - - - -
-
- )} - -); +
+ + + + +
+
+ )} + + ); +}; CategoryCreatePage.displayName = "CategoryCreatePage"; export default CategoryCreatePage; diff --git a/src/categories/components/CategoryDeleteDialog/CategoryDeleteDialog.tsx b/src/categories/components/CategoryDeleteDialog/CategoryDeleteDialog.tsx index 3fb36f4c8..7cb5b8aba 100644 --- a/src/categories/components/CategoryDeleteDialog/CategoryDeleteDialog.tsx +++ b/src/categories/components/CategoryDeleteDialog/CategoryDeleteDialog.tsx @@ -11,8 +11,9 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; const styles = (theme: Theme) => createStyles({ @@ -36,27 +37,33 @@ const CategoryDeleteDialog = withStyles(styles, { name: "CategoryDeleteDialog" })(({ classes, name, open, onConfirm, onClose }: CategoryDeleteDialogProps) => ( - {i18n.t("Delete category", { context: "title" })} - - {{name}}?", - { name } - ) - }} + + + + + + {name} + }} + /> + diff --git a/src/categories/components/CategoryDetailsForm/CategoryDetailsForm.tsx b/src/categories/components/CategoryDetailsForm/CategoryDetailsForm.tsx index cffbd9579..75332a772 100644 --- a/src/categories/components/CategoryDetailsForm/CategoryDetailsForm.tsx +++ b/src/categories/components/CategoryDetailsForm/CategoryDetailsForm.tsx @@ -4,11 +4,12 @@ import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import { RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import FormSpacer from "@saleor/components/FormSpacer"; import RichTextEditor from "@saleor/components/RichTextEditor"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { maybe } from "../../../misc"; import { CategoryDetails_category } from "../../types/CategoryDetails"; @@ -40,15 +41,21 @@ export const CategoryDetailsForm = withStyles(styles, { onChange, errors }: CategoryDetailsFormProps) => { + const intl = useIntl(); + return ( - + <>
JSON.parse(category.descriptionJson))} name="description" onChange={onChange} diff --git a/src/categories/components/CategoryList/CategoryList.tsx b/src/categories/components/CategoryList/CategoryList.tsx index 293e04830..2db043d80 100644 --- a/src/categories/components/CategoryList/CategoryList.tsx +++ b/src/categories/components/CategoryList/CategoryList.tsx @@ -12,13 +12,13 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; 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"; @@ -87,112 +87,132 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })( onPreviousPage, onUpdateListSettings, onRowClick - }: CategoryListProps) => ( - - {!isRoot && ( - - {i18n.t("Add subcategory")} - - } - /> - )} -
- - - {i18n.t("Category Name", { context: "object" })} - - - {i18n.t("Subcategories", { context: "object" })} - - - {i18n.t("No. Products", { context: "object" }).replace(" ", "\xa0")} - - - - - - - - - {renderCollection( - categories, - category => { - const isSelected = category ? isChecked(category.id) : false; + }: CategoryListProps) => { + const intl = useIntl(); - return ( - - - toggle(category.id)} - /> - - - {category && category.name ? category.name : } - - - {category && - category.children && - category.children.totalCount !== undefined ? ( - category.children.totalCount + return ( + + {!isRoot && ( + + + + } + /> + )} +
+ + + + + + + + + + + + + + + + + + {renderCollection( + categories, + category => { + const isSelected = category ? isChecked(category.id) : false; + + return ( + + + toggle(category.id)} + /> + + + {category && category.name ? category.name : } + + + {category && + category.children && + category.children.totalCount !== undefined ? ( + category.children.totalCount + ) : ( + + )} + + + {category && + category.products && + category.products.totalCount !== undefined ? ( + category.products.totalCount + ) : ( + + )} + + + ); + }, + () => ( + + + {isRoot ? ( + ) : ( - - )} - - - {category && - category.products && - category.products.totalCount !== undefined ? ( - category.products.totalCount - ) : ( - + )} - ); - }, - () => ( - - - {isRoot - ? i18n.t("No categories found") - : i18n.t("No subcategories found")} - - - ) - )} - -
- - ) + ) + )} + + + + ); + } ); CategoryList.displayName = "CategoryList"; export default CategoryList; diff --git a/src/categories/components/CategoryListPage/CategoryListPage.tsx b/src/categories/components/CategoryListPage/CategoryListPage.tsx index c3829c4bd..a3428f4fc 100644 --- a/src/categories/components/CategoryListPage/CategoryListPage.tsx +++ b/src/categories/components/CategoryListPage/CategoryListPage.tsx @@ -1,10 +1,11 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import CategoryList from "../CategoryList"; @@ -36,31 +37,38 @@ export const CategoryListPage: React.StatelessComponent = ({ toggle, toggleAll, toolbar -}) => ( - - - - - - -); +}) => { + const intl = useIntl(); + return ( + + + + + + + ); +}; CategoryListPage.displayName = "CategoryListPage"; export default CategoryListPage; diff --git a/src/categories/components/CategoryProducts/CategoryProducts.tsx b/src/categories/components/CategoryProducts/CategoryProducts.tsx index 56d7ec5fe..3615351bd 100644 --- a/src/categories/components/CategoryProducts/CategoryProducts.tsx +++ b/src/categories/components/CategoryProducts/CategoryProducts.tsx @@ -13,13 +13,13 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "../../../i18n"; -import { maybe, renderCollection } from "../../../misc"; +import { maybe, renderCollection } from "@saleor/misc"; const styles = (theme: Theme) => createStyles({ @@ -61,76 +61,96 @@ export const ProductList = withStyles(styles, { name: "ProductList" })( onNextPage, onPreviousPage, onRowClick - }: ProductListProps) => ( - - - {i18n.t("Add product")} - - } - /> - - - - {(products === undefined || products.length > 0) && } - - {i18n.t("Name", { context: "object" })} - - {i18n.t("Type", { context: "object" })} - - - - - - - - - {renderCollection( - products, - product => ( - - product.thumbnail.url)} + }: ProductListProps) => { + const intl = useIntl(); + + return ( + + + + + } + /> +
+ + + {(products === undefined || products.length > 0) && } + + - - {product ? ( - - {product.name} - - ) : ( - - )} - - - {product && product.productType ? ( - product.productType.name - ) : ( - - )} - - - ), - () => ( - - {i18n.t("No products found")} - - ) - )} - -
-
- ) + + + + + + + + + + + + + {renderCollection( + products, + product => ( + + product.thumbnail.url)} + /> + + {product ? ( + + {product.name} + + ) : ( + + )} + + + {product && product.productType ? ( + product.productType.name + ) : ( + + )} + + + ), + () => ( + + + + + + ) + )} + + + + ); + } ); ProductList.displayName = "CategoryProductList"; export default ProductList; diff --git a/src/categories/components/CategoryProductsCard/CategoryProductsCard.tsx b/src/categories/components/CategoryProductsCard/CategoryProductsCard.tsx index e862eb68b..42124f661 100644 --- a/src/categories/components/CategoryProductsCard/CategoryProductsCard.tsx +++ b/src/categories/components/CategoryProductsCard/CategoryProductsCard.tsx @@ -1,10 +1,10 @@ import Button from "@material-ui/core/Button"; import Card from "@material-ui/core/Card"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import ProductList from "@saleor/components/ProductList"; -import i18n from "../../../i18n"; import { ListActions, PageListProps } from "../../../types"; import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails"; @@ -29,35 +29,50 @@ export const CategoryProductsCard: React.StatelessComponent< toggle, toggleAll, toolbar -}) => ( - - - {i18n.t("Add product")} - - } - /> - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + } + /> + + + ); +}; CategoryProductsCard.displayName = "CategoryProductsCard"; export default CategoryProductsCard; diff --git a/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.tsx b/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.tsx index 2b944e305..05e02cdbb 100644 --- a/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.tsx +++ b/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.tsx @@ -1,5 +1,6 @@ import { RawDraftContentState } from "draft-js"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; @@ -10,7 +11,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import { Tab, TabContainer } from "@saleor/components/Tab"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { TabListActions, UserError } from "../../../types"; import CategoryDetailsForm from "../../components/CategoryDetailsForm"; @@ -96,6 +97,7 @@ export const CategoryUpdatePage: React.StatelessComponent< toggle, toggleAll }: CategoryUpdatePageProps) => { + const intl = useIntl(); const initialData: FormData = category ? { backgroundImageAlt: maybe(() => category.backgroundImage.alt, ""), @@ -120,7 +122,9 @@ export const CategoryUpdatePage: React.StatelessComponent< > {({ data, change, errors, submit, hasChanged }) => ( - {i18n.t("Categories")} + + {intl.formatMessage(sectionNames.categories)} + - {i18n.t("Subcategories")} + - {i18n.t("Products")} + @@ -204,9 +215,6 @@ export const CategoryUpdatePage: React.StatelessComponent< onCancel={onBack} onDelete={onDelete} onSave={submit} - labels={{ - delete: i18n.t("Delete category") - }} state={saveButtonBarState} disabled={disabled || !hasChanged} /> diff --git a/src/categories/index.tsx b/src/categories/index.tsx index 01178b737..5c120659c 100644 --- a/src/categories/index.tsx +++ b/src/categories/index.tsx @@ -1,8 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; + +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { categoryAddPath, categoryListPath, @@ -56,16 +58,20 @@ const CategoryList: React.StatelessComponent> = ({ return ; }; -const Component = () => ( - <> - - - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + + ); +}; export default Component; diff --git a/src/categories/views/CategoryCreate.tsx b/src/categories/views/CategoryCreate.tsx index 03f42f937..c56212c4f 100644 --- a/src/categories/views/CategoryCreate.tsx +++ b/src/categories/views/CategoryCreate.tsx @@ -1,9 +1,9 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import CategoryCreatePage from "../components/CategoryCreatePage"; import { TypedCategoryCreateMutation } from "../mutations"; @@ -19,10 +19,15 @@ export const CategoryCreateView: React.StatelessComponent< > = ({ parentId }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleSuccess = (data: CategoryCreate) => { if (data.categoryCreate.errors.length === 0) { - notify({ text: i18n.t("Category created") }); + notify({ + text: intl.formatMessage({ + defaultMessage: "Category created" + }) + }); navigate(categoryUrl(data.categoryCreate.category.id)); } }; @@ -42,7 +47,12 @@ export const CategoryCreateView: React.StatelessComponent< return ( <> - + { if (data.categoryDelete.errors.length === 0) { notify({ - text: i18n.t("Category deleted", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Category deleted" }) }); navigate(categoryListUrl()); @@ -140,7 +142,7 @@ export const CategoryDetails: React.StatelessComponent< if (data.categoryBulkDelete.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Categories removed") + text: intl.formatMessage(commonMessages.savedChanges) }); refetch(); reset(); @@ -151,7 +153,7 @@ export const CategoryDetails: React.StatelessComponent< if (data.productBulkDelete.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Products removed") + text: intl.formatMessage(commonMessages.savedChanges) }); refetch(); reset(); @@ -319,32 +321,36 @@ export const CategoryDetails: React.StatelessComponent< deleteCategory({ variables: { id } }) } open={params.action === "delete"} - title={i18n.t("Delete category", { - context: "modal title" + title={intl.formatMessage({ + defaultMessage: "Delete category", + description: "dialog title" })} variant="delete" > - {{ categoryName }}?
", - { - categoryName: maybe( - () => data.category.name - ), - context: "modal message" - } - ) - }} - /> - {i18n.t( - "Remember that this will also remove all products assigned to this category." - )} + + {maybe( + () => data.category.name, + "..." + )} + + ) + }} + /> + + + params.ids.length > 0) + } confirmButtonState={ categoryBulkDeleteMutationState } @@ -354,27 +360,32 @@ export const CategoryDetails: React.StatelessComponent< variables: { ids: params.ids } }) } - title={i18n.t("Remove categories")} + title={intl.formatMessage({ + defaultMessage: "Delete categories", + description: "dialog title" + })} variant="delete" > - {{ number }} categories?", - { - number: maybe( - () => - params.ids.length.toString(), - "..." - ) - } - ) - }} - /> - {i18n.t( - "Remember that this will also remove all products assigned to this category." - )} + params.ids.length + ), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + + + - {{ number }} products?", - { - number: maybe( - () => - params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + {" "} + + params.ids.length + ), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + ); diff --git a/src/categories/views/CategoryList.tsx b/src/categories/views/CategoryList.tsx index a9520ceb5..1064d9ccc 100644 --- a/src/categories/views/CategoryList.tsx +++ b/src/categories/views/CategoryList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useBulkActions from "@saleor/hooks/useBulkActions"; @@ -10,7 +11,6 @@ import useNavigator from "@saleor/hooks/useNavigator"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; -import i18n from "@saleor/i18n"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import { CategoryListPage } from "../components/CategoryListPage/CategoryListPage"; @@ -39,6 +39,8 @@ export const CategoryList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.CATEGORY_LIST ); + const intl = useIntl(); + const paginationState = createPaginationState(settings.rowNumber, params); return ( @@ -124,26 +126,26 @@ export const CategoryList: React.StatelessComponent = ({ }) } open={params.action === "delete"} - title={i18n.t("Remove categories")} + title={intl.formatMessage({ + defaultMessage: "Delete categories", + description: "dialog title" + })} variant="delete" > - {{ number }} categories?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} ) }} /> - {i18n.t( - "Remember that this will also remove all products assigned to this category." - )} + diff --git a/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx b/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx index 78e92fa01..b9677c595 100644 --- a/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx +++ b/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx @@ -2,6 +2,7 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import { ContentState, convertToRaw, RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; @@ -14,7 +15,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { UserError } from "../../../types"; import CollectionDetails from "../CollectionDetails/CollectionDetails"; import { CollectionImage } from "../CollectionImage/CollectionImage"; @@ -63,105 +64,108 @@ const CollectionCreatePage: React.StatelessComponent< saveButtonBarState, onBack, onSubmit -}: CollectionCreatePageProps) => ( -
- {({ change, data, errors: formErrors, hasChanged, submit }) => ( - - {i18n.t("Collections")} - - -
- - - - change({ - target: { - name: "backgroundImage", - value: { - url: null, - value: null - } - } - } as any) - } - onImageUpload={file => - change({ - target: { - name: "backgroundImage", - value: { - url: URL.createObjectURL(file), - value: file - } - } - } as any) - } - onChange={change} - data={data} - /> - - -
-
+}: CollectionCreatePageProps) => { + const intl = useIntl(); + + return ( + + {({ change, data, errors: formErrors, hasChanged, submit }) => ( + + + {intl.formatMessage(sectionNames.collections)} + + +
- - - - - - + + + + change({ + target: { + name: "backgroundImage", + value: { + url: null, + value: null + } + } + } as any) + } + onImageUpload={file => + change({ + target: { + name: "backgroundImage", + value: { + url: URL.createObjectURL(file), + value: file + } + } + } as any) + } + onChange={change} + data={data} + /> + +
-
-
- -
- )} -
-); +
+
+ + + + + + +
+
+ + +
+ )} + + ); +}; CollectionCreatePage.displayName = "CollectionCreatePage"; export default CollectionCreatePage; diff --git a/src/collections/components/CollectionDetails/CollectionDetails.tsx b/src/collections/components/CollectionDetails/CollectionDetails.tsx index db44e3ccb..56374d94f 100644 --- a/src/collections/components/CollectionDetails/CollectionDetails.tsx +++ b/src/collections/components/CollectionDetails/CollectionDetails.tsx @@ -4,13 +4,14 @@ import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import { RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import FormSpacer from "@saleor/components/FormSpacer"; import RichTextEditor from "@saleor/components/RichTextEditor"; -import i18n from "../../../i18n"; -import { maybe } from "../../../misc"; -import { FormErrors } from "../../../types"; +import { commonMessages } from "@saleor/intl"; +import { maybe } from "@saleor/misc"; +import { FormErrors } from "@saleor/types"; import { CollectionDetails_collection } from "../../types/CollectionDetails"; const styles = createStyles({ @@ -38,33 +39,42 @@ const CollectionDetails = withStyles(styles, { name: "CollectionDetails" })( data, onChange, errors - }: CollectionDetailsProps) => ( - - - - { + const intl = useIntl(); + + return ( + + - - JSON.parse(collection.descriptionJson))} - label={i18n.t("Description")} - name="description" - disabled={disabled} - onChange={onChange} - /> - - - ) + + + + JSON.parse(collection.descriptionJson))} + label={intl.formatMessage(commonMessages.description)} + name="description" + disabled={disabled} + onChange={onChange} + /> + + + ); + } ); CollectionDetails.displayName = "CollectionDetails"; export default CollectionDetails; diff --git a/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx b/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx index 9c97df6ea..91e565d7a 100644 --- a/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx +++ b/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx @@ -1,5 +1,6 @@ import { RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; @@ -12,7 +13,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { ListActions, PageListProps } from "../../../types"; import { CollectionDetails_collection } from "../../types/CollectionDetails"; @@ -57,6 +58,8 @@ const CollectionDetailsPage: React.StatelessComponent< onSubmit, ...collectionProductsProps }: CollectionDetailsPageProps) => { + const intl = useIntl(); + return (
{({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Collections")} + + {intl.formatMessage(sectionNames.collections)} + collection.name)} />
@@ -104,12 +109,10 @@ const CollectionDetailsPage: React.StatelessComponent< description={data.seoDescription} disabled={disabled} descriptionPlaceholder="" - helperText={i18n.t( - "Add search engine title and description to make this collection easier to find", - { - context: "help text" - } - )} + helperText={intl.formatMessage({ + defaultMessage: + "Add search engine title and description to make this collection easier to find" + })} title={data.seoTitle} titlePlaceholder={maybe(() => collection.name)} onChange={change} @@ -128,8 +131,9 @@ const CollectionDetailsPage: React.StatelessComponent< disabled={disabled} name="isFeatured" onChange={change} - label={i18n.t("Feature on Homepage", { - context: "button" + label={intl.formatMessage({ + defaultMessage: "Feature on Homepage", + description: "switch button" })} /> diff --git a/src/collections/components/CollectionImage/CollectionImage.tsx b/src/collections/components/CollectionImage/CollectionImage.tsx index 05758727c..1ebd5eb85 100644 --- a/src/collections/components/CollectionImage/CollectionImage.tsx +++ b/src/collections/components/CollectionImage/CollectionImage.tsx @@ -6,6 +6,7 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Button from "@material-ui/core/Button"; import Card from "@material-ui/core/Card"; @@ -15,7 +16,7 @@ import Hr from "@saleor/components/Hr"; import ImageTile from "@saleor/components/ImageTile"; import ImageUpload from "@saleor/components/ImageUpload"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { CollectionDetails_collection_backgroundImage } from "../../types/CollectionDetails"; const styles = (theme: Theme) => @@ -51,7 +52,7 @@ const styles = (theme: Theme) => } }); -export interface CollectionImageProps extends WithStyles { +export interface CollectionImageProps { data: { backgroundImageAlt: string; }; @@ -62,80 +63,81 @@ export interface CollectionImageProps extends WithStyles { } export const CollectionImage = withStyles(styles)( - class CollectionImageComponent extends React.Component< - CollectionImageProps, - {} - > { - imgInputAnchor = React.createRef(); + ({ + classes, + data, + onImageUpload, + image, + onChange, + onImageDelete + }: CollectionImageProps & WithStyles) => { + const anchor = React.useRef(); + const intl = useIntl(); - clickImgInput = () => this.imgInputAnchor.current.click(); + const handleImageUploadButtonClick = () => anchor.current.click(); - render() { - const { - classes, - data, - onImageUpload, - image, - onChange, - onImageDelete - } = this.props; - return ( - - - - onImageUpload(event.target.files[0])} - type="file" - ref={this.imgInputAnchor} - /> - - } - /> - {image === undefined ? ( - -
-
- -
-
-
- ) : image === null ? ( - - ) : ( - - - - )} - {image && ( + return ( + + -
- - - + + onImageUpload(event.target.files[0])} + type="file" + ref={anchor} + /> - )} -
- ); - } + } + /> + {image === undefined ? ( + +
+
+ +
+
+
+ ) : image === null ? ( + + ) : ( + + + + )} + {image && ( + <> +
+ + + + + )} +
+ ); } ); CollectionImage.displayName = "CollectionImage"; diff --git a/src/collections/components/CollectionList/CollectionList.tsx b/src/collections/components/CollectionList/CollectionList.tsx index fd63f69a3..ff5763b18 100644 --- a/src/collections/components/CollectionList/CollectionList.tsx +++ b/src/collections/components/CollectionList/CollectionList.tsx @@ -11,13 +11,13 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { CollectionList_collections_edges_node } from "../../types/CollectionList"; @@ -68,107 +68,124 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })( toggle, toggleAll, toolbar - }: CollectionListProps) => ( - - - - - {i18n.t("Category Name", { context: "table cell" })} - - - {i18n - .t("No. Products", { context: "table cell" }) - .replace(" ", "\xa0")} - - - {i18n.t("Availability", { context: "table cell" })} - - - - - - - - - {renderCollection( - collections, - collection => { - const isSelected = collection ? isChecked(collection.id) : false; - return ( - - - toggle(collection.id)} - /> - - - {maybe( - () => collection.name, - - )} - - - {maybe( - () => collection.products.totalCount, - - )} - - - {maybe( - () => ( - - ), - - )} + }: CollectionListProps) => { + const intl = useIntl(); + + return ( + +
+ + + + + + + + + + + + + + + + + + {renderCollection( + collections, + collection => { + const isSelected = collection + ? isChecked(collection.id) + : false; + return ( + + + toggle(collection.id)} + /> + + + {maybe( + () => collection.name, + + )} + + + {maybe( + () => collection.products.totalCount, + + )} + + + {maybe( + () => ( + + ), + + )} + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No collections found")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); CollectionList.displayName = "CollectionList"; export default CollectionList; diff --git a/src/collections/components/CollectionListPage/CollectionListPage.tsx b/src/collections/components/CollectionListPage/CollectionListPage.tsx index b115569fb..6101c3843 100644 --- a/src/collections/components/CollectionListPage/CollectionListPage.tsx +++ b/src/collections/components/CollectionListPage/CollectionListPage.tsx @@ -1,10 +1,11 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import { Container } from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { CollectionList_collections_edges_node } from "../../types/CollectionList"; import CollectionList from "../CollectionList/CollectionList"; @@ -17,21 +18,28 @@ const CollectionListPage: React.StatelessComponent = ({ disabled, onAdd, ...listProps -}) => ( - - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + ); +}; CollectionListPage.displayName = "CollectionListPage"; export default CollectionListPage; diff --git a/src/collections/components/CollectionProducts/CollectionProducts.tsx b/src/collections/components/CollectionProducts/CollectionProducts.tsx index b957a489a..2fb889616 100644 --- a/src/collections/components/CollectionProducts/CollectionProducts.tsx +++ b/src/collections/components/CollectionProducts/CollectionProducts.tsx @@ -14,6 +14,7 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Checkbox from "@saleor/components/Checkbox"; @@ -24,7 +25,6 @@ import TableCellAvatar, { } from "@saleor/components/TableCellAvatar"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ListActions, PageListProps } from "../../../types"; import { CollectionDetails_collection } from "../../types/CollectionDetails"; @@ -83,137 +83,165 @@ const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })( toggle, toggleAll, toolbar - }: CollectionProductsProps) => ( - - - ) - } - toolbar={ - - } - /> - - collection.products.edges.map(edge => edge.node))} - toggleAll={toggleAll} - toolbar={toolbar} - > - - - {i18n.t("Name", { context: "table header" })} - - - - {i18n.t("Type", { context: "table header" })} - - - {i18n.t("Published", { context: "table header" })} - - - - - - pageInfo.hasNextPage)} - onNextPage={onNextPage} - hasPreviousPage={maybe(() => pageInfo.hasPreviousPage)} - onPreviousPage={onPreviousPage} - /> - - - - {renderCollection( - maybe(() => collection.products.edges.map(edge => edge.node)), - product => { - const isSelected = product ? isChecked(product.id) : false; + }: CollectionProductsProps) => { + const intl = useIntl(); - return ( - - - toggle(product.id)} - /> - - product.thumbnail.url)} + return ( + + collection.name, "...") + } + ) + ) : ( + + ) + } + toolbar={ + + } + /> +
+ + collection.products.edges.map(edge => edge.node) + )} + toggleAll={toggleAll} + toolbar={toolbar} + > + + + + + + + + + + + + + + + + pageInfo.hasNextPage)} + onNextPage={onNextPage} + hasPreviousPage={maybe(() => pageInfo.hasPreviousPage)} + onPreviousPage={onPreviousPage} + /> + + + + {renderCollection( + maybe(() => collection.products.edges.map(edge => edge.node)), + product => { + const isSelected = product ? isChecked(product.id) : false; + + return ( + - {maybe(() => product.name, )} - - - {maybe( - () => product.productType.name, - - )} - - - {maybe( - () => ( - - ), - - )} - - - onProductUnassign(product.id, event)} + + toggle(product.id)} + /> + + product.thumbnail.url)} > - - + {maybe(() => product.name, )} + + + {maybe( + () => product.productType.name, + + )} + + + {maybe( + () => ( + + ), + + )} + + + onProductUnassign(product.id, event)} + > + + + + + ); + }, + () => ( + + + + - ); - }, - () => ( - - - - {i18n.t("No products found")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); CollectionProducts.displayName = "CollectionProducts"; export default CollectionProducts; diff --git a/src/collections/containers/CollectionOperations.tsx b/src/collections/containers/CollectionOperations.tsx index 694d85915..36d5bc12f 100644 --- a/src/collections/containers/CollectionOperations.tsx +++ b/src/collections/containers/CollectionOperations.tsx @@ -31,30 +31,28 @@ import { } from "../types/UnassignCollectionProduct"; interface CollectionUpdateOperationsProps { - children: ( - props: { - updateCollectionWithHomepage: PartialMutationProviderOutput< - CollectionUpdateWithHomepage, - CollectionUpdateWithHomepageVariables - >; - assignProduct: PartialMutationProviderOutput< - CollectionAssignProduct, - CollectionAssignProductVariables - >; - unassignProduct: PartialMutationProviderOutput< - UnassignCollectionProduct, - UnassignCollectionProductVariables - >; - updateCollection: PartialMutationProviderOutput< - CollectionUpdate, - CollectionUpdateVariables - >; - removeCollection: PartialMutationProviderOutput< - RemoveCollection, - RemoveCollectionVariables - >; - } - ) => React.ReactNode; + children: (props: { + updateCollectionWithHomepage: PartialMutationProviderOutput< + CollectionUpdateWithHomepage, + CollectionUpdateWithHomepageVariables + >; + assignProduct: PartialMutationProviderOutput< + CollectionAssignProduct, + CollectionAssignProductVariables + >; + unassignProduct: PartialMutationProviderOutput< + UnassignCollectionProduct, + UnassignCollectionProductVariables + >; + updateCollection: PartialMutationProviderOutput< + CollectionUpdate, + CollectionUpdateVariables + >; + removeCollection: PartialMutationProviderOutput< + RemoveCollection, + RemoveCollectionVariables + >; + }) => React.ReactNode; onUpdate: (data: CollectionUpdate) => void; onProductAssign: (data: CollectionAssignProduct) => void; onProductUnassign: (data: UnassignCollectionProduct) => void; diff --git a/src/collections/index.tsx b/src/collections/index.tsx index 75a11dd04..a5f0fce6a 100644 --- a/src/collections/index.tsx +++ b/src/collections/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { collectionAddPath, collectionListPath, @@ -39,14 +40,18 @@ const CollectionDetails: React.StatelessComponent< ); }; -const Component = () => ( - <> - - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + ); +}; export default Component; diff --git a/src/collections/views/CollectionCreate.tsx b/src/collections/views/CollectionCreate.tsx index 29c1de5c6..9b747b30e 100644 --- a/src/collections/views/CollectionCreate.tsx +++ b/src/collections/views/CollectionCreate.tsx @@ -1,9 +1,9 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import { CollectionCreateInput } from "../../types/globalTypes"; import CollectionCreatePage from "../components/CollectionCreatePage/CollectionCreatePage"; @@ -11,15 +11,16 @@ import { TypedCollectionCreateMutation } from "../mutations"; import { CreateCollection } from "../types/CreateCollection"; import { collectionListUrl, collectionUrl } from "../urls"; -export const CollectionCreate: React.StatelessComponent<{}> = () => { +export const CollectionCreate: React.FC = () => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleCollectionCreateSuccess = (data: CreateCollection) => { if (data.collectionCreate.errors.length === 0) { notify({ - text: i18n.t("Created collection", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Created collection" }) }); navigate(collectionUrl(data.collectionCreate.collection.id)); @@ -45,7 +46,12 @@ export const CollectionCreate: React.StatelessComponent<{}> = () => { ); return ( <> - + data.collectionCreate.errors, [])} onBack={() => navigate(collectionListUrl())} diff --git a/src/collections/views/CollectionDetails.tsx b/src/collections/views/CollectionDetails.tsx index bdabd01c1..9d1668512 100644 --- a/src/collections/views/CollectionDetails.tsx +++ b/src/collections/views/CollectionDetails.tsx @@ -1,6 +1,7 @@ import Button from "@material-ui/core/Button"; import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import AssignProductDialog from "@saleor/components/AssignProductDialog"; @@ -11,9 +12,9 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; +import { commonMessages } from "@saleor/intl"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; import SearchProducts from "../../containers/SearchProducts"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { CollectionInput } from "../../types/globalTypes"; @@ -47,6 +48,7 @@ export const CollectionDetails: React.StatelessComponent< params.ids ); const paginate = usePaginator(); + const intl = useIntl(); const closeModal = () => navigate( @@ -77,9 +79,7 @@ export const CollectionDetails: React.StatelessComponent< const handleCollectionUpdate = (data: CollectionUpdate) => { if (data.collectionUpdate.errors.length === 0) { notify({ - text: i18n.t("Updated collection", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(collectionUrl(id)); } else { @@ -98,8 +98,8 @@ export const CollectionDetails: React.StatelessComponent< const handleProductAssign = (data: CollectionAssignProduct) => { if (data.collectionAddProducts.errors.length === 0) { notify({ - text: i18n.t("Added product to collection", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Added product to collection" }) }); navigate(collectionUrl(id), true); @@ -109,8 +109,8 @@ export const CollectionDetails: React.StatelessComponent< const handleProductUnassign = (data: UnassignCollectionProduct) => { if (data.collectionRemoveProducts.errors.length === 0) { notify({ - text: i18n.t("Removed product from collection", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Deleted product from collection" }) }); reset(); @@ -121,8 +121,8 @@ export const CollectionDetails: React.StatelessComponent< const handleCollectionRemove = (data: RemoveCollection) => { if (data.collectionDelete.errors.length === 0) { notify({ - text: i18n.t("Removed collection", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Deleted collection" }) }); navigate(collectionListUrl()); @@ -272,7 +272,10 @@ export const CollectionDetails: React.StatelessComponent< ) } > - {i18n.t("Unassign")} + } isChecked={isSelected} @@ -308,25 +311,24 @@ export const CollectionDetails: React.StatelessComponent< onClose={closeModal} onConfirm={() => removeCollection.mutate({ id })} open={params.action === "remove"} - title={i18n.t("Remove collection", { - context: "modal title" + title={intl.formatMessage({ + defaultMessage: "Delete Collection", + description: "dialog title" })} variant="delete" > - {{ collectionName }}?", - { - collectionName: maybe( - () => data.collection.name, - "..." - ), - context: "modal" - } - ) - }} - /> + + + {maybe(() => data.collection.name, "...")} + + ) + }} + /> + - {{ number }} products?", - { - context: "modal", - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} + ) + }} + /> + - {i18n.t( - "Are you sure you want to remove collection's image?" - )} + diff --git a/src/collections/views/CollectionList.tsx b/src/collections/views/CollectionList.tsx index 90a3f6686..0b7345126 100644 --- a/src/collections/views/CollectionList.tsx +++ b/src/collections/views/CollectionList.tsx @@ -3,6 +3,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useBulkActions from "@saleor/hooks/useBulkActions"; @@ -12,7 +13,7 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import CollectionListPage from "../components/CollectionListPage/CollectionListPage"; @@ -47,6 +48,7 @@ export const CollectionList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.COLLECTION_LIST ); + const intl = useIntl(); const closeModal = () => navigate( @@ -79,7 +81,7 @@ export const CollectionList: React.StatelessComponent = ({ const handleCollectionBulkDelete = (data: CollectionBulkDelete) => { if (data.collectionBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed collections") + text: intl.formatMessage(commonMessages.savedChanges) }); refetch(); reset(); @@ -90,7 +92,7 @@ export const CollectionList: React.StatelessComponent = ({ const handleCollectionBulkPublish = (data: CollectionBulkPublish) => { if (data.collectionBulkPublish.errors.length === 0) { notify({ - text: i18n.t("Changed publication status") + text: intl.formatMessage(commonMessages.savedChanges) }); refetch(); reset(); @@ -147,13 +149,19 @@ export const CollectionList: React.StatelessComponent = ({ openModal("unpublish", listElements) } > - {i18n.t("Unpublish")} + = ({ toggleAll={toggleAll} /> params.ids.length > 0) + } onClose={closeModal} confirmButtonState={bulkPublishTransitionState} onConfirm={() => @@ -181,24 +192,33 @@ export const CollectionList: React.StatelessComponent = ({ }) } variant="default" - title={i18n.t("Publish collections")} + title={intl.formatMessage({ + defaultMessage: "Publish collections", + description: "dialog title" + })} > - {{ number }} collections?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + params.ids.length > 0) + } onClose={closeModal} confirmButtonState={bulkPublishTransitionState} onConfirm={() => @@ -210,24 +230,33 @@ export const CollectionList: React.StatelessComponent = ({ }) } variant="default" - title={i18n.t("Unpublish collections")} + title={intl.formatMessage({ + defaultMessage: "Unpublish collections", + description: "dialog title" + })} > - {{ number }} collections?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + params.ids.length > 0) + } onClose={closeModal} confirmButtonState={bulkDeleteTransitionState} onConfirm={() => @@ -238,21 +267,27 @@ export const CollectionList: React.StatelessComponent = ({ }) } variant="delete" - title={i18n.t("Remove collections")} + title={intl.formatMessage({ + defaultMessage: "Delete collections", + description: "dialog title" + })} > - {{ number }} collections?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + ); diff --git a/src/components/ActionDialog/ActionDialog.tsx b/src/components/ActionDialog/ActionDialog.tsx index 3a5df3a46..9ae6807a6 100644 --- a/src/components/ActionDialog/ActionDialog.tsx +++ b/src/components/ActionDialog/ActionDialog.tsx @@ -11,8 +11,9 @@ import { } from "@material-ui/core/styles"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; -import i18n from "../../i18n"; +import { buttonMessages } from "@saleor/intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "../ConfirmButton/ConfirmButton"; @@ -50,31 +51,35 @@ const ActionDialog = withStyles(styles, { name: "ActionDialog" })( variant, onConfirm, onClose - }: ActionDialogProps) => ( - - {title} - {children} - - - - {confirmButtonLabel || - (variant === "delete" - ? i18n.t("Delete", { context: "button" }) - : i18n.t("Confirm", { context: "button" }))} - - - - ) + }: ActionDialogProps) => { + const intl = useIntl(); + + return ( + + {title} + {children} + + + + {confirmButtonLabel || + (variant === "delete" + ? intl.formatMessage(buttonMessages.delete) + : intl.formatMessage(buttonMessages.confirm))} + + + + ); + } ); ActionDialog.displayName = "ActionDialog"; export default ActionDialog; diff --git a/src/components/AddressEdit/AddressEdit.tsx b/src/components/AddressEdit/AddressEdit.tsx index 7960d3180..cd62da230 100644 --- a/src/components/AddressEdit/AddressEdit.tsx +++ b/src/components/AddressEdit/AddressEdit.tsx @@ -6,9 +6,10 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import { AddressTypeInput } from "@saleor/customers/types"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; import { FormErrors } from "@saleor/types"; import FormSpacer from "../FormSpacer"; import SingleAutocompleteSelectField, { @@ -44,144 +45,164 @@ const AddressEdit = withStyles(styles, { name: "AddressEdit" })( errors, onChange, onCountryChange - }: AddressEditProps) => ( - <> -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - - - - -
-
- -
-
- -
-
+ }: AddressEditProps) => { + const intl = useIntl(); - -
-
- + return ( + <> +
+
+ +
+
+ +
-
- + +
+
+ +
+
+ +
-
- - ) + + + + + +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ + ); + } ); AddressEdit.displayName = "AddressEdit"; export default AddressEdit; diff --git a/src/components/AppLayout/AppLayout.tsx b/src/components/AppLayout/AppLayout.tsx index 68bd40eca..01651ebc4 100644 --- a/src/components/AppLayout/AppLayout.tsx +++ b/src/components/AppLayout/AppLayout.tsx @@ -17,6 +17,7 @@ import { import classNames from "classnames"; import React from "react"; import SVG from "react-inlinesvg"; +import { FormattedMessage, useIntl } from "react-intl"; import { RouteComponentProps, withRouter } from "react-router"; import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg"; @@ -27,14 +28,13 @@ import useLocalStorage from "@saleor/hooks/useLocalStorage"; import useNavigator from "@saleor/hooks/useNavigator"; import useTheme from "@saleor/hooks/useTheme"; import useUser from "@saleor/hooks/useUser"; -import i18n from "@saleor/i18n"; import ArrowDropdown from "@saleor/icons/ArrowDropdown"; import Container from "../Container"; import AppActionContext from "./AppActionContext"; import AppHeaderContext from "./AppHeaderContext"; import { appLoaderHeight, drawerWidth, drawerWidthExpanded } from "./consts"; import MenuList from "./MenuList"; -import menuStructure from "./menuStructure"; +import createMenuStructure from "./menuStructure"; import ResponsiveDrawer from "./ResponsiveDrawer"; import ThemeSwitch from "./ThemeSwitch"; @@ -108,9 +108,7 @@ const styles = (theme: Theme) => }, isMenuSmallDark: { "&:hover": { - background: `linear-gradient(0deg, rgba(25, 195, 190, 0.1), rgba(25, 195, 190, 0.1)), ${ - theme.palette.background.paper - }` + background: `linear-gradient(0deg, rgba(25, 195, 190, 0.1), rgba(25, 195, 190, 0.1)), ${theme.palette.background.paper}` }, border: `solid 1px #252728`, transition: `background ${theme.transitions.duration.shorter}ms` @@ -277,6 +275,9 @@ const AppLayout = withStyles(styles, { const anchor = React.useRef(); const { logout, user } = useUser(); const navigate = useNavigator(); + const intl = useIntl(); + + const menuStructure = createMenuStructure(intl); const handleLogout = () => { close(); @@ -430,9 +431,10 @@ const AppLayout = withStyles(styles, { className={classes.userMenuItem} onClick={handleLogout} > - {i18n.t("Log out", { - context: "button" - })} + diff --git a/src/components/AppLayout/MenuList.tsx b/src/components/AppLayout/MenuList.tsx index b22603f3e..74c7a3891 100644 --- a/src/components/AppLayout/MenuList.tsx +++ b/src/components/AppLayout/MenuList.tsx @@ -8,13 +8,17 @@ import Typography from "@material-ui/core/Typography"; import classNames from "classnames"; import React from "react"; import SVG from "react-inlinesvg"; +import { FormattedMessage, useIntl } from "react-intl"; import { matchPath } from "react-router"; import configureIcon from "@assets/images/menu-configure-icon.svg"; import useTheme from "@saleor/hooks/useTheme"; +import { sectionNames } from "@saleor/intl"; import { User } from "../../auth/types/User"; -import { configurationMenu, configurationMenuUrl } from "../../configuration"; -import i18n from "../../i18n"; +import { + configurationMenuUrl, + createConfigurationMenu +} from "../../configuration"; import { createHref } from "../../misc"; import { orderDraftListUrl, orderListUrl } from "../../orders/urls"; import MenuNested from "./MenuNested"; @@ -167,6 +171,7 @@ const MenuList = withStyles(styles, { name: "MenuList" })( isActive: false, label: null }); + const intl = useIntl(); const handleSubMenu = itemLabel => { setActiveSubMenu({ @@ -300,7 +305,7 @@ const MenuList = withStyles(styles, { name: "MenuList" })( ); })} {renderConfigure && - configurationMenu.filter(menuItem => + createConfigurationMenu(intl).filter(menuItem => user.permissions .map(perm => perm.code) .includes(menuItem.permission) @@ -323,7 +328,7 @@ const MenuList = withStyles(styles, { name: "MenuList" })( [classes.menuListItemTextHide]: !isMenuSmall })} > - {i18n.t("Configuration")} +
diff --git a/src/components/AppLayout/menuStructure.ts b/src/components/AppLayout/menuStructure.ts index 1c13c5dfa..3e1c46da2 100644 --- a/src/components/AppLayout/menuStructure.ts +++ b/src/components/AppLayout/menuStructure.ts @@ -2,7 +2,6 @@ import { categoryListUrl } from "../../categories/urls"; import { collectionListUrl } from "../../collections/urls"; import { customerListUrl } from "../../customers/urls"; import { saleListUrl, voucherListUrl } from "../../discounts/urls"; -import i18n from "../../i18n"; import { orderDraftListUrl, orderListUrl } from "../../orders/urls"; import { productListUrl } from "../../products/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 ordersIcon from "@assets/images/menu-orders-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 { ariaLabel: string; @@ -24,88 +25,91 @@ export interface IMenuItem { url?: string; } -const menuStructure: IMenuItem[] = [ - { - ariaLabel: "home", - icon: homeIcon, - label: i18n.t("Home", { context: "Menu label" }), - url: "/" - }, - { - ariaLabel: "catalogue", - children: [ - { - ariaLabel: "products", - label: i18n.t("Products", { context: "Menu label" }), - url: productListUrl() - }, - { - ariaLabel: "categories", - label: i18n.t("Categories", { context: "Menu label" }), - url: categoryListUrl() - }, - { - ariaLabel: "collections", - label: i18n.t("Collections", { context: "Menu label" }), - url: collectionListUrl() - } - ], - icon: catalogIcon, - label: i18n.t("Catalog", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_PRODUCTS - }, - { - ariaLabel: "orders", - children: [ - { - ariaLabel: "orders", - label: i18n.t("Orders", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_ORDERS, - url: orderListUrl() - }, - { - ariaLabel: "order drafts", - label: i18n.t("Drafts", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_ORDERS, - url: orderDraftListUrl() - } - ], - icon: ordersIcon, - label: i18n.t("Orders", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_ORDERS - }, - { - ariaLabel: "customers", - icon: customerIcon, - label: i18n.t("Customers", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_USERS, - url: customerListUrl() - }, +function createMenuStructure(intl: IntlShape): IMenuItem[] { + return [ + { + ariaLabel: "home", + icon: homeIcon, + label: intl.formatMessage(sectionNames.home), + url: "/" + }, + { + ariaLabel: "catalogue", + children: [ + { + ariaLabel: "products", + label: intl.formatMessage(sectionNames.products), + url: productListUrl() + }, + { + ariaLabel: "categories", + label: intl.formatMessage(sectionNames.categories), + url: categoryListUrl() + }, + { + ariaLabel: "collections", + label: intl.formatMessage(sectionNames.collections), + url: collectionListUrl() + } + ], + icon: catalogIcon, + label: intl.formatMessage(commonMessages.catalog), + permission: PermissionEnum.MANAGE_PRODUCTS + }, + { + ariaLabel: "orders", + children: [ + { + ariaLabel: "orders", + label: intl.formatMessage(sectionNames.orders), + permission: PermissionEnum.MANAGE_ORDERS, + url: orderListUrl() + }, + { + ariaLabel: "order drafts", + label: intl.formatMessage(commonMessages.drafts), + permission: PermissionEnum.MANAGE_ORDERS, + url: orderDraftListUrl() + } + ], + icon: ordersIcon, + label: intl.formatMessage(sectionNames.orders), + permission: PermissionEnum.MANAGE_ORDERS + }, + { + ariaLabel: "customers", + icon: customerIcon, + label: intl.formatMessage(sectionNames.customers), + permission: PermissionEnum.MANAGE_USERS, + url: customerListUrl() + }, - { - ariaLabel: "discounts", - children: [ - { - ariaLabel: "sales", - label: i18n.t("Sales", { context: "Menu label" }), - url: saleListUrl() - }, - { - ariaLabel: "vouchers", - label: i18n.t("Vouchers", { context: "Menu label" }), - url: voucherListUrl() - } - ], - icon: discountsIcon, - label: i18n.t("Discounts", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_DISCOUNTS - }, - { - ariaLabel: "translations", - icon: translationIcon, - label: i18n.t("Translations", { context: "Menu label" }), - permission: PermissionEnum.MANAGE_TRANSLATIONS, - url: languageListUrl - } -]; -export default menuStructure; + { + ariaLabel: "discounts", + children: [ + { + ariaLabel: "sales", + label: intl.formatMessage(sectionNames.sales), + url: saleListUrl() + }, + { + ariaLabel: "vouchers", + label: intl.formatMessage(sectionNames.vouchers), + url: voucherListUrl() + } + ], + icon: discountsIcon, + label: intl.formatMessage(commonMessages.discounts), + permission: PermissionEnum.MANAGE_DISCOUNTS + }, + { + ariaLabel: "translations", + icon: translationIcon, + label: intl.formatMessage(sectionNames.translations), + permission: PermissionEnum.MANAGE_TRANSLATIONS, + url: languageListUrl + } + ]; +} + +export default createMenuStructure; diff --git a/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx b/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx index b8504b729..a6e76df8a 100644 --- a/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx +++ b/src/components/AssignCategoryDialog/AssignCategoryDialog.tsx @@ -11,14 +11,15 @@ import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; 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 FormSpacer from "@saleor/components/FormSpacer"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; +import { buttonMessages } from "@saleor/intl"; import { SearchCategories_categories_edges_node } from "../../containers/SearchCategories/types/SearchCategories"; -import i18n from "../../i18n"; import Checkbox from "../Checkbox"; export interface FormData { @@ -85,6 +86,7 @@ const AssignCategoriesDialog = withStyles(styles, { onFetch, onSubmit }: AssignCategoriesDialogProps) => { + const intl = useIntl(); const [query, onQueryChange] = useSearchQuery(onFetch); const [selectedCategories, setSelectedCategories] = React.useState< SearchCategories_categories_edges_node[] @@ -100,17 +102,22 @@ const AssignCategoriesDialog = withStyles(styles, { fullWidth maxWidth="sm" > - {i18n.t("Assign Categories")} + + + - {i18n.t("Assign categories", { context: "button" })} + diff --git a/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx b/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx index a8e316a4a..388ae5a7b 100644 --- a/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx +++ b/src/components/AssignCollectionDialog/AssignCollectionDialog.tsx @@ -11,9 +11,10 @@ import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; -import i18n from "@saleor/i18n"; +import { buttonMessages } from "@saleor/intl"; import { SearchCollections_collections_edges_node } from "../../containers/SearchCollections/types/SearchCollections"; import Checkbox from "../Checkbox"; import ConfirmButton, { @@ -85,6 +86,7 @@ const AssignCollectionDialog = withStyles(styles, { onFetch, onSubmit }: AssignCollectionDialogProps) => { + const intl = useIntl(); const [query, onQueryChange] = useSearchQuery(onFetch); const [selectedCollections, setSelectedCollections] = React.useState< SearchCollections_collections_edges_node[] @@ -100,17 +102,22 @@ const AssignCollectionDialog = withStyles(styles, { fullWidth maxWidth="sm" > - {i18n.t("Assign Collection")} + + + - {i18n.t("Assign collections", { context: "button" })} + diff --git a/src/components/AssignProductDialog/AssignProductDialog.tsx b/src/components/AssignProductDialog/AssignProductDialog.tsx index 8e3bdfddf..255741583 100644 --- a/src/components/AssignProductDialog/AssignProductDialog.tsx +++ b/src/components/AssignProductDialog/AssignProductDialog.tsx @@ -11,6 +11,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState @@ -18,7 +19,7 @@ import ConfirmButton, { import FormSpacer from "@saleor/components/FormSpacer"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; -import i18n from "@saleor/i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { SearchProducts_products_edges_node } from "../../containers/SearchProducts/types/SearchProducts"; import Checkbox from "../Checkbox"; @@ -88,6 +89,7 @@ const AssignProductDialog = withStyles(styles, { onFetch, onSubmit }: AssignProductDialogProps & WithStyles) => { + const intl = useIntl(); const [query, onQueryChange] = useSearchQuery(onFetch); const [selectedProducts, setSelectedProducts] = React.useState< SearchProducts_products_edges_node[] @@ -103,21 +105,24 @@ const AssignProductDialog = withStyles(styles, { fullWidth maxWidth="sm" > - {i18n.t("Assign Product")} + + + - {i18n.t("Assign products", { context: "button" })} + diff --git a/src/components/AutocompleteSelectMenu/AutocompleteSelectMenu.tsx b/src/components/AutocompleteSelectMenu/AutocompleteSelectMenu.tsx index 20a458e5f..209128e4e 100644 --- a/src/components/AutocompleteSelectMenu/AutocompleteSelectMenu.tsx +++ b/src/components/AutocompleteSelectMenu/AutocompleteSelectMenu.tsx @@ -11,8 +11,9 @@ import TextField from "@material-ui/core/TextField"; import ArrowBack from "@material-ui/icons/ArrowBack"; import Downshift from "downshift"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { getMenuItemByPath, IMenu, @@ -153,7 +154,7 @@ const AutocompleteSelectMenu = withStyles(styles, { } > - {i18n.t("Back")} + )} {(menuPath.length @@ -176,7 +177,7 @@ const AutocompleteSelectMenu = withStyles(styles, { ) : ( - {i18n.t("No results")} + )} diff --git a/src/components/ColumnPicker/ColumnPickerButton.tsx b/src/components/ColumnPicker/ColumnPickerButton.tsx index bdd7dde47..b57b8991e 100644 --- a/src/components/ColumnPicker/ColumnPickerButton.tsx +++ b/src/components/ColumnPicker/ColumnPickerButton.tsx @@ -5,8 +5,7 @@ import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; import makeStyles from "@material-ui/styles/makeStyles"; import classNames from "classnames"; import React from "react"; - -import i18n from "@saleor/i18n"; +import { FormattedMessage } from "react-intl"; interface ColumnPickerButtonProps { active: boolean; @@ -51,9 +50,10 @@ const ColumnPickerButton: React.FC = props => { onClick={onClick} variant="outlined" > - {i18n.t("Columns", { - context: "select visible columns button" - })} + = props => { - {i18n.t( - "{{ numberOfSelected }} columns selected out of {{ numberOfTotal }}", - { - context: "pick columns to display", +
@@ -109,14 +110,14 @@ const ColumnPickerContent: React.FC = props => { >
diff --git a/src/components/ConfirmButton/ConfirmButton.tsx b/src/components/ConfirmButton/ConfirmButton.tsx index 07185213a..e105eafbc 100644 --- a/src/components/ConfirmButton/ConfirmButton.tsx +++ b/src/components/ConfirmButton/ConfirmButton.tsx @@ -8,10 +8,10 @@ import { WithStyles } from "@material-ui/core/styles"; import CheckIcon from "@material-ui/icons/Check"; +import { buttonMessages } from "@saleor/intl"; import classNames from "classnames"; import React from "react"; - -import i18n from "../../i18n"; +import { FormattedMessage } from "react-intl"; export type ConfirmButtonTransitionState = | "loading" @@ -170,14 +170,11 @@ const ConfirmButton = withStyles(styles)( displayCompletedActionState })} > - {transitionState === "error" && displayCompletedActionState - ? i18n.t("Error", { - context: "button" - }) - : children || - i18n.t("Confirm", { - context: "button" - })} + {transitionState === "error" && displayCompletedActionState ? ( + + ) : ( + children || + )} ); diff --git a/src/components/CountryList/CountryList.tsx b/src/components/CountryList/CountryList.tsx index ff0893a96..f7fe18a79 100644 --- a/src/components/CountryList/CountryList.tsx +++ b/src/components/CountryList/CountryList.tsx @@ -16,10 +16,10 @@ import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; import DeleteIcon from "@material-ui/icons/Delete"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../i18n"; import { maybe, renderCollection } from "../../misc"; import { CountryFragment } from "../../taxes/types/CountryFragment"; @@ -99,7 +99,10 @@ const CountryList = withStyles(styles, { title={title} toolbar={ } /> @@ -110,10 +113,13 @@ const CountryList = withStyles(styles, { - {i18n.t("{{ number }} Countries", { - context: "number of countries", - number: maybe(() => countries.length.toString(), "...") - })} + countries.length.toString(), "...") + }} + /> { componentDidMount() { this.intervalId = window.setInterval( () => this.setState({ date: Date.now() }), - 10_000 + 10000 ); } diff --git a/src/components/DeleteFilterTabDialog/DeleteFilterTabDialog.tsx b/src/components/DeleteFilterTabDialog/DeleteFilterTabDialog.tsx index 651304cce..c18663cba 100644 --- a/src/components/DeleteFilterTabDialog/DeleteFilterTabDialog.tsx +++ b/src/components/DeleteFilterTabDialog/DeleteFilterTabDialog.tsx @@ -1,7 +1,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; -import i18n from "../../i18n"; import ActionDialog from "../ActionDialog"; import { ConfirmButtonTransitionState } from "../ConfirmButton"; @@ -19,28 +19,31 @@ const DeleteFilterTabDialog: React.FC = ({ onSubmit, open, tabName -}) => ( - - {{ name }} search tab?", - { - name: tabName - } - ) - }} - /> - -); +}) => { + const intl = useIntl(); + + return ( + + + {tabName} + }} + /> + + + ); +}; DeleteFilterTabDialog.displayName = "DeleteFilterTabDialog"; export default DeleteFilterTabDialog; diff --git a/src/components/ErrorMessageCard/ErrorMessageCard.tsx b/src/components/ErrorMessageCard/ErrorMessageCard.tsx index f3d4ed6ab..5912d20d4 100644 --- a/src/components/ErrorMessageCard/ErrorMessageCard.tsx +++ b/src/components/ErrorMessageCard/ErrorMessageCard.tsx @@ -2,9 +2,7 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import Typography from "@material-ui/core/Typography"; import React from "react"; - -import i18n from "../../i18n"; - +import { FormattedMessage } from "react-intl"; interface ErrorMessageCardProps { message: string; } @@ -15,7 +13,7 @@ const ErrorMessageCard: React.StatelessComponent = ({ - {i18n.t("Error", { context: "title" })} + {message} diff --git a/src/components/ErrorPage/ErrorPage.tsx b/src/components/ErrorPage/ErrorPage.tsx index 485cc22d9..38b374c22 100644 --- a/src/components/ErrorPage/ErrorPage.tsx +++ b/src/components/ErrorPage/ErrorPage.tsx @@ -8,9 +8,9 @@ import { import Typography from "@material-ui/core/Typography"; import React from "react"; import SVG from "react-inlinesvg"; +import { FormattedMessage } from "react-intl"; import notFoundImage from "@assets/images/what.svg"; -import i18n from "../../i18n"; export interface ErrorPageProps extends WithStyles { onBack: () => void; @@ -68,14 +68,16 @@ const ErrorPage = withStyles(styles, { name: "NotFoundPage" })(
- {i18n.t("Ooops!...")} + - {i18n.t("Error")} + - {i18n.t("We've encountered a problem...")} - {i18n.t("Don't worry, everything is gonna be fine")} + + + +
@@ -85,7 +87,10 @@ const ErrorPage = withStyles(styles, { name: "NotFoundPage" })( variant="contained" onClick={onBack} > - {i18n.t("Back to home", { context: "button" })} +
diff --git a/src/components/FileUpload/FileUpload.tsx b/src/components/FileUpload/FileUpload.tsx index 6d07f8fa4..6c71f53f7 100644 --- a/src/components/FileUpload/FileUpload.tsx +++ b/src/components/FileUpload/FileUpload.tsx @@ -2,7 +2,7 @@ import Button from "@material-ui/core/Button"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; -import i18n from "../../i18n"; +import { FormattedMessage } from "react-intl"; const styles = createStyles({ fileUploadField: { @@ -42,7 +42,10 @@ const FileUpload = withStyles(styles, { name: "FileUpload" })( value={value} />
) diff --git a/src/components/Filter/Filter.tsx b/src/components/Filter/Filter.tsx index fa32d49ae..a68e682df 100644 --- a/src/components/Filter/Filter.tsx +++ b/src/components/Filter/Filter.tsx @@ -13,9 +13,9 @@ import Typography from "@material-ui/core/Typography"; import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage } from "react-intl"; import { FilterContent } from "."; -import i18n from "../../i18n"; import { FilterContentSubmitData } from "./FilterContent"; import { IFilter } from "./types"; @@ -103,7 +103,10 @@ const Filter = withStyles(styles, { name: "Filter" })( onClick={() => setFilterMenuOpened(!isFilterMenuOpened)} > - {i18n.t("Add Filter")} + = ({ filters, onSubmit }) => { + const intl = useIntl(); const [menuValue, setMenuValue] = React.useState(""); const [filterValue, setFilterValue] = React.useState(""); const classes = useStyles({}); @@ -72,7 +73,9 @@ const FilterContent: React.FC = ({ } }} value={menus ? menus[0].value : menuValue} - placeholder={i18n.t("Select Filter...")} + placeholder={intl.formatMessage({ + defaultMessage: "Select Filter..." + })} /> {menus && menus.map( @@ -95,7 +98,9 @@ const FilterContent: React.FC = ({ ? menuValue : menus[filterItemIndex - 1].label.toString() } - placeholder={i18n.t("Select Filter...")} + placeholder={intl.formatMessage({ + defaultMessage: "Select Filter..." + })} /> ) @@ -124,7 +129,10 @@ const FilterContent: React.FC = ({ }) } > - {i18n.t("Add filter")} + )} diff --git a/src/components/Filter/FilterElement.tsx b/src/components/Filter/FilterElement.tsx index e9735d5a0..da4e1d8f6 100644 --- a/src/components/Filter/FilterElement.tsx +++ b/src/components/Filter/FilterElement.tsx @@ -2,8 +2,8 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/styles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; -import i18n from "../../i18n"; import Calendar from "../../icons/Calendar"; import FormSpacer from "../FormSpacer"; import PriceField from "../PriceField"; @@ -41,6 +41,7 @@ const FilterElement: React.FC = ({ onChange, value }) => { + const intl = useIntl(); const classes = useStyles({}); if (filter.data.type === FieldType.date) { @@ -62,7 +63,9 @@ const FilterElement: React.FC = ({ } else if (filter.data.type === FieldType.rangeDate) { return ( <> - {i18n.t("from")} + + + = ({ }} /> - {i18n.t("to")} + + + = ({ } else if (filter.data.type === FieldType.range) { return ( <> - {i18n.t("from")} + + + = ({ }} /> - {i18n.t("to")} + + + = ({ } else if (filter.data.type === FieldType.rangePrice) { return ( <> - {i18n.t("from")} + + + = ({ }} /> - {i18n.t("to")} + + + = ({ } }} value={value as string} - placeholder={i18n.t("Select Filter...")} + placeholder={intl.formatMessage({ + defaultMessage: "Select Filter..." + })} onChange={event => onChange(event.target.value)} /> ); diff --git a/src/components/FilterBar/FilterBar.tsx b/src/components/FilterBar/FilterBar.tsx index f5adc696d..7f81046c5 100644 --- a/src/components/FilterBar/FilterBar.tsx +++ b/src/components/FilterBar/FilterBar.tsx @@ -1,6 +1,6 @@ import React from "react"; +import { useIntl } from "react-intl"; -import i18n from "../../i18n"; import { FilterProps } from "../../types"; import Debounce from "../Debounce"; import { IFilter } from "../Filter/types"; @@ -28,6 +28,7 @@ const FilterBar: React.FC = ({ onTabChange, onFilterDelete }) => { + const intl = useIntl(); const [search, setSearch] = React.useState(initialSearch); React.useEffect(() => setSearch(initialSearch), [currentTab, initialSearch]); @@ -47,7 +48,9 @@ const FilterBar: React.FC = ({ {isCustom && ( undefined} - label={i18n.t("Custom Filter")} + label={intl.formatMessage({ + defaultMessage: "Custom Filter" + })} /> )} diff --git a/src/components/FilterCard/FilterCard.tsx b/src/components/FilterCard/FilterCard.tsx index 30d18c6a8..25d150874 100644 --- a/src/components/FilterCard/FilterCard.tsx +++ b/src/components/FilterCard/FilterCard.tsx @@ -4,8 +4,7 @@ import CardHeader from "@material-ui/core/CardHeader"; import IconButton from "@material-ui/core/IconButton"; import RefreshIcon from "@material-ui/icons/Refresh"; import React from "react"; - -import i18n from "../../i18n"; +import { useIntl } from "react-intl"; export interface FilterCardProps { handleClear(); @@ -14,20 +13,26 @@ export interface FilterCardProps { const FilterCard: React.StatelessComponent = ({ children, handleClear -}) => ( - - - - -
- } - title={i18n.t("Filters")} - /> - {children} - - -); +}) => { + const intl = useIntl(); + + return ( + +
+ + + + } + title={intl.formatMessage({ + defaultMessage: "Filters" + })} + /> + {children} + +
+ ); +}; FilterCard.displayName = "FilterCard"; export default FilterCard; diff --git a/src/components/ImageUpload/ImageUpload.tsx b/src/components/ImageUpload/ImageUpload.tsx index 92ae65717..431b96186 100644 --- a/src/components/ImageUpload/ImageUpload.tsx +++ b/src/components/ImageUpload/ImageUpload.tsx @@ -8,8 +8,7 @@ import { fade } from "@material-ui/core/styles/colorManipulator"; import Typography from "@material-ui/core/Typography"; import classNames from "classnames"; import React from "react"; - -import i18n from "../../i18n"; +import { FormattedMessage } from "react-intl"; import ImageIcon from "../../icons/Image"; import Dropzone from "../Dropzone"; @@ -95,9 +94,10 @@ export const ImageUpload = withStyles(styles, { name: "ImageUpload" })( - {i18n.t("Drop here to upload", { - context: "image upload" - })} +
diff --git a/src/components/LanguageSwitch/LanguageSwitch.tsx b/src/components/LanguageSwitch/LanguageSwitch.tsx index c0aa61af2..fb0396797 100644 --- a/src/components/LanguageSwitch/LanguageSwitch.tsx +++ b/src/components/LanguageSwitch/LanguageSwitch.tsx @@ -15,8 +15,8 @@ import Typography from "@material-ui/core/Typography"; import ArrowDropDown from "@material-ui/icons/ArrowDropDown"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; import { LanguageCodeEnum } from "../../types/globalTypes"; import { ShopInfo_shop_languages } from "../Shop/types/ShopInfo"; @@ -110,11 +110,14 @@ const LanguageSwitch = withStyles(styles, { name: "LanguageSwitch" })( onLanguageChange(lang.code); }} > - {i18n.t("{{ languageName }} - {{ languageCode }}", { - context: "button", - languageCode: lang.code, - languageName: lang.language - })} + ))} diff --git a/src/components/ListField/ListField.tsx b/src/components/ListField/ListField.tsx index ff05b84b6..7dee20c3a 100644 --- a/src/components/ListField/ListField.tsx +++ b/src/components/ListField/ListField.tsx @@ -8,7 +8,8 @@ import { } from "@material-ui/core/styles"; import TextField, { StandardTextFieldProps } from "@material-ui/core/TextField"; import React from "react"; -import i18n from "../../i18n"; +import { FormattedMessage } from "react-intl"; + import Chip from "../Chip"; interface ListFieldState { @@ -105,7 +106,7 @@ const ListField = withStyles(styles)( color="primary" onClick={this.handleValueAdd} > - {i18n.t("Add", { context: "button" })} + ) }} diff --git a/src/components/Locale/Locale.tsx b/src/components/Locale/Locale.tsx index d1d4fd023..34f455a1f 100644 --- a/src/components/Locale/Locale.tsx +++ b/src/components/Locale/Locale.tsx @@ -1,11 +1,44 @@ import React from "react"; +import { IntlProvider } from "react-intl"; -export const LocaleContext = React.createContext("en"); +export type LocaleContextType = string; +export const LocaleContext = React.createContext("en"); -const { Consumer: LocaleConsumer, Provider } = LocaleContext; +const { Consumer: LocaleConsumer, Provider: RawLocaleProvider } = LocaleContext; -const LocaleProvider = ({ children }) => { - return {children}; +enum Locale { + EN = "en", + EN_GB = "en-gb", + EN_US = "en-us" +} + +type LocaleMessages = Record; +const localeData: Record = { + [Locale.EN]: {}, + [Locale.EN_GB]: {}, + [Locale.EN_US]: {} }; -export { LocaleConsumer, LocaleProvider }; +function getMatchingLocale(): Locale { + const localeEntries = Object.entries(Locale); + + for (const preferredLocale of navigator.languages) { + for (const localeEntry of localeEntries) { + if (localeEntry[1].toLowerCase() === preferredLocale.toLowerCase()) { + return Locale[localeEntry[0]]; + } + } + } +} + +const LocaleProvider: React.FC = ({ children }) => { + const [locale] = React.useState(getMatchingLocale()); + + return ( + + {children} + + ); +}; + +export { LocaleConsumer, LocaleProvider, RawLocaleProvider }; diff --git a/src/components/MoneyRange/MoneyRange.tsx b/src/components/MoneyRange/MoneyRange.tsx index afcb8a564..0b4a6d12f 100644 --- a/src/components/MoneyRange/MoneyRange.tsx +++ b/src/components/MoneyRange/MoneyRange.tsx @@ -1,6 +1,5 @@ import React from "react"; - -import i18n from "../../i18n"; +import { useIntl } from "react-intl"; import { LocaleConsumer } from "../Locale"; import IMoney from "../Money"; @@ -18,29 +17,48 @@ const formatMoney = (money: IMoney, locale: string) => export const MoneyRange: React.StatelessComponent = ({ from, to -}) => ( - - {locale => - from && to - ? i18n.t("{{ fromMoney }} - {{ toMoney }}", { - context: "money", - fromMoney: formatMoney(from, locale), - toMoney: formatMoney(to, locale) - }) - : from && !to - ? i18n.t("from {{ money }}", { - context: "money", - money: formatMoney(from, locale) - }) - : !from && to - ? i18n.t("to {{ money }}", { - context: "money", - money: formatMoney(to, locale) - }) - : "-" - } - -); +}) => { + const intl = useIntl(); + + return ( + + {locale => + from && to + ? intl.formatMessage( + { + defaultMessage: "{fromMoney} - {toMoney}", + description: "money" + }, + { + fromMoney: formatMoney(from, locale), + toMoney: formatMoney(to, locale) + } + ) + : from && !to + ? intl.formatMessage( + { + defaultMessage: "from {money}", + description: "money" + }, + { + money: formatMoney(from, locale) + } + ) + : !from && to + ? intl.formatMessage( + { + defaultMessage: "to {money}", + description: "money" + }, + { + money: formatMoney(to, locale) + } + ) + : "-" + } + + ); +}; MoneyRange.displayName = "MoneyRange"; export default MoneyRange; diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx index 66a46f145..7215ec83a 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx @@ -13,12 +13,12 @@ import Typography from "@material-ui/core/Typography"; import CloseIcon from "@material-ui/icons/Close"; import Downshift, { ControllerStateAndHelpers } from "downshift"; import React from "react"; +import { FormattedMessage } from "react-intl"; import { compareTwoStrings } from "string-similarity"; import { fade } from "@material-ui/core/styles/colorManipulator"; import Checkbox from "@saleor/components/Checkbox"; import Debounce, { DebounceProps } from "@saleor/components/Debounce"; -import i18n from "@saleor/i18n"; import ArrowDropdownIcon from "@saleor/icons/ArrowDropdown"; import Hr from "../Hr"; @@ -244,10 +244,13 @@ export const MultiAutocompleteSelectFieldComponent = withStyles(styles, { data-tc="multiautocomplete-select-option" > - {i18n.t("Add new value: {{ value }}", { - context: "add custom option", - value: inputValue - })} + )} @@ -259,7 +262,7 @@ export const MultiAutocompleteSelectFieldComponent = withStyles(styles, { component="div" data-tc="multiautocomplete-select-no-options" > - {i18n.t("No results found")} + ) )} diff --git a/src/components/MultiSelectField/MultiSelectField.tsx b/src/components/MultiSelectField/MultiSelectField.tsx index 5fdda787c..5bf3743c1 100644 --- a/src/components/MultiSelectField/MultiSelectField.tsx +++ b/src/components/MultiSelectField/MultiSelectField.tsx @@ -11,8 +11,8 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; import Checkbox from "../Checkbox"; const styles = (theme: Theme) => @@ -110,7 +110,9 @@ export const MultiSelectField = withStyles(styles, { ); }) ) : ( - {i18n.t("No results found")} + + + )} {hint && {hint}} diff --git a/src/components/NotFoundPage/NotFoundPage.tsx b/src/components/NotFoundPage/NotFoundPage.tsx index 236e905a0..cac5306bc 100644 --- a/src/components/NotFoundPage/NotFoundPage.tsx +++ b/src/components/NotFoundPage/NotFoundPage.tsx @@ -8,9 +8,9 @@ import { import Typography from "@material-ui/core/Typography"; import React from "react"; import SVG from "react-inlinesvg"; +import { FormattedMessage } from "react-intl"; import notFoundImage from "@assets/images/not-found-404.svg"; -import i18n from "@saleor/i18n"; const styles = (theme: Theme) => createStyles({ @@ -65,12 +65,14 @@ const NotFoundPage = withStyles(styles, { name: "NotFoundPage" })(
- {i18n.t("Ooops!...")} + - {i18n.t("Something's missing")} + + + + - {i18n.t("Sorry, the page was not found")}
diff --git a/src/components/ProductList/ProductList.tsx b/src/components/ProductList/ProductList.tsx index 949cad712..32dd47362 100644 --- a/src/components/ProductList/ProductList.tsx +++ b/src/components/ProductList/ProductList.tsx @@ -10,12 +10,12 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import TableCellAvatar, { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar"; import { ProductListColumns } from "@saleor/config"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { isSelected } from "@saleor/utils/lists"; @@ -97,6 +97,7 @@ export const ProductList = withStyles(styles, { name: "ProductList" })( onUpdateListSettings, onRowClick }: ProductListProps) => { + const intl = useIntl(); const displayColumn = React.useCallback( (column: ProductListColumns) => isSelected(column, settings.columns, (a, b) => a === b), @@ -124,22 +125,28 @@ export const ProductList = withStyles(styles, { name: "ProductList" })( > - {i18n.t("Name", { context: "object" })} + {displayColumn("productType") && ( - {i18n.t("Type", { context: "object" })} + )} {displayColumn("isPublished") && ( - {i18n.t("Published", { context: "object" })} + )} {displayColumn("price") && ( - {i18n.t("Price", { context: "object" })} + )} @@ -205,11 +212,13 @@ export const ProductList = withStyles(styles, { name: "ProductList" })( ( - {i18n.t("No products found")} + ) diff --git a/src/components/RadioGroupField/RadioGroupField.tsx b/src/components/RadioGroupField/RadioGroupField.tsx index b22446312..3c97b2ef7 100644 --- a/src/components/RadioGroupField/RadioGroupField.tsx +++ b/src/components/RadioGroupField/RadioGroupField.tsx @@ -8,8 +8,7 @@ import RadioGroup from "@material-ui/core/RadioGroup"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import classNames from "classnames"; import React from "react"; - -import i18n from "../../i18n"; +import { FormattedMessage } from "react-intl"; const styles = createStyles({ formControl: { @@ -83,7 +82,9 @@ export const RadioGroupField = withStyles(styles, { /> )) ) : ( - {i18n.t("No results found")} + + + )} {hint && {hint}} diff --git a/src/components/RichTextEditor/ImageEntity.tsx b/src/components/RichTextEditor/ImageEntity.tsx index 4bf9721c0..d81beaaed 100644 --- a/src/components/RichTextEditor/ImageEntity.tsx +++ b/src/components/RichTextEditor/ImageEntity.tsx @@ -13,8 +13,7 @@ import { import DeleteIcon from "@material-ui/icons/Delete"; import { ContentState } from "draft-js"; import React from "react"; - -import i18n from "../../i18n"; +import { FormattedMessage } from "react-intl"; interface ImageEntityProps { children: React.ReactNode; @@ -88,7 +87,10 @@ const ImageEntity = withStyles(styles, { }} color="primary" > - {i18n.t("Replace")} + onRemove(entityKey)}> diff --git a/src/components/RichTextEditor/ImageSource.tsx b/src/components/RichTextEditor/ImageSource.tsx index d238bc09f..766681eb9 100644 --- a/src/components/RichTextEditor/ImageSource.tsx +++ b/src/components/RichTextEditor/ImageSource.tsx @@ -6,8 +6,9 @@ import DialogTitle from "@material-ui/core/DialogTitle"; import TextField from "@material-ui/core/TextField"; import { AtomicBlockUtils, EditorState, EntityInstance } from "draft-js"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; -import i18n from "../../i18n"; +import { buttonMessages } from "@saleor/intl"; import Form from "../Form"; interface ImageSourceProps { @@ -21,16 +22,19 @@ interface ImageSourceProps { onClose: () => void; } -class ImageSource extends React.Component { - submit = (href: string) => { - const { - editorState, - entity, - entityKey, - entityType, - onComplete - } = this.props; +const ImageSource: React.FC = ({ + editorState, + entity, + entityKey, + entityType, + onComplete, + onClose +}) => { + const intl = useIntl(); + const initial = entity ? entity.getData().href : ""; + + const handleSubmit = (href: string) => { if (href) { const content = editorState.getCurrentContent(); if (entity) { @@ -60,41 +64,44 @@ class ImageSource extends React.Component { } }; - render() { - const { entity, onClose } = this.props; - const initial = entity ? entity.getData().href : ""; + return ( + +
handleSubmit(href)} + > + {({ data, change, submit }) => ( + <> + + + + + + + + + + + + )} +
+
+ ); +}; - return ( - -
this.submit(href)} - > - {({ data, change, submit }) => ( - <> - {i18n.t("Add Image Link")} - - - - - - - - - )} -
-
- ); - } -} export default ImageSource; diff --git a/src/components/RichTextEditor/LinkEntity.tsx b/src/components/RichTextEditor/LinkEntity.tsx index ac8080b43..436d8451e 100644 --- a/src/components/RichTextEditor/LinkEntity.tsx +++ b/src/components/RichTextEditor/LinkEntity.tsx @@ -14,8 +14,9 @@ import Typography from "@material-ui/core/Typography"; import DeleteIcon from "@material-ui/icons/Delete"; import { ContentState } from "draft-js"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; +import { buttonMessages } from "@saleor/intl"; import Link from "../Link"; interface LinkEntityProps { @@ -107,7 +108,7 @@ const LinkEntity = withStyles(styles, { }} color="primary" > - {i18n.t("Edit")} + onRemove(entityKey)}> diff --git a/src/components/RichTextEditor/LinkSource.tsx b/src/components/RichTextEditor/LinkSource.tsx index bbf17eda0..892cef14e 100644 --- a/src/components/RichTextEditor/LinkSource.tsx +++ b/src/components/RichTextEditor/LinkSource.tsx @@ -6,8 +6,9 @@ import DialogTitle from "@material-ui/core/DialogTitle"; import TextField from "@material-ui/core/TextField"; import { EditorState, EntityInstance, RichUtils } from "draft-js"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; -import i18n from "../../i18n"; +import { buttonMessages } from "@saleor/intl"; import Form from "../Form"; interface LinkSourceProps { @@ -20,10 +21,17 @@ interface LinkSourceProps { onClose: () => void; } -class LinkSource extends React.Component { - submit = (url: string) => { - const { editorState, entityType, onComplete } = this.props; +const LinkSource: React.FC = ({ + editorState, + entity, + entityType, + onComplete, + onClose +}) => { + const intl = useIntl(); + const initial = entity ? entity.getData().url : ""; + const handleSubmit = (url: string) => { if (url) { const content = editorState.getCurrentContent(); const contentWithEntity = content.createEntity( @@ -47,41 +55,44 @@ class LinkSource extends React.Component { } }; - render() { - const { entity, onClose } = this.props; - const initial = entity ? entity.getData().url : ""; + return ( + +
handleSubmit(url)} + > + {({ data, change, submit }) => ( + <> + + + + + + + + + + + + )} +
+
+ ); +}; - return ( - -
this.submit(url)} - > - {({ data, change, submit }) => ( - <> - {i18n.t("Add or Edit Link")} - - - - - - - - - )} -
-
- ); - } -} export default LinkSource; diff --git a/src/components/RowNumberSelect/RowNumberSelect.tsx b/src/components/RowNumberSelect/RowNumberSelect.tsx index 2a670e7ae..4ae050f80 100644 --- a/src/components/RowNumberSelect/RowNumberSelect.tsx +++ b/src/components/RowNumberSelect/RowNumberSelect.tsx @@ -3,8 +3,8 @@ import Select from "@material-ui/core/Select"; import { Theme } from "@material-ui/core/styles"; import { createStyles, makeStyles, useTheme } from "@material-ui/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; import { ListSettings } from "../../types"; const useStyles = makeStyles( @@ -51,7 +51,9 @@ const RowNumberSelect: React.FC = ({ const classes = useStyles({ theme }); return (
- {i18n.t("No of Rows:")} + + + {hint && {hint}} diff --git a/src/components/TableFilter/FilterChips.tsx b/src/components/TableFilter/FilterChips.tsx index 273829c19..176c53b44 100644 --- a/src/components/TableFilter/FilterChips.tsx +++ b/src/components/TableFilter/FilterChips.tsx @@ -6,8 +6,8 @@ import Typography from "@material-ui/core/Typography"; import ClearIcon from "@material-ui/icons/Clear"; import { createStyles, makeStyles, useTheme } from "@material-ui/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; import Filter, { FilterContentSubmitData, IFilter } from "../Filter"; import Hr from "../Hr"; import Link from "../Link"; @@ -163,9 +163,19 @@ export const FilterChips: React.FC = ({ ))}
{isCustomSearch ? ( - {i18n.t("Save Custom Search")} + + + ) : ( - {i18n.t("Delete Search")} + + + )} ) : ( diff --git a/src/components/TableFilter/index.ts b/src/components/TableFilter/index.ts index d2d907900..5cb8830ab 100644 --- a/src/components/TableFilter/index.ts +++ b/src/components/TableFilter/index.ts @@ -1,5 +1,4 @@ export { default } from "./FilterTabs"; -export { Filter } from "./FilterChips"; export * from "./FilterTabs"; export * from "./FilterTab"; export * from "./FilterChips"; diff --git a/src/components/TableHead/TableHead.tsx b/src/components/TableHead/TableHead.tsx index d82f71d92..9305e263f 100644 --- a/src/components/TableHead/TableHead.tsx +++ b/src/components/TableHead/TableHead.tsx @@ -13,10 +13,10 @@ import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage } from "react-intl"; import { Node } from "../../types"; -import i18n from "../../i18n"; import Checkbox from "../Checkbox"; export interface TableHeadProps extends MuiTableHeadProps { @@ -129,9 +129,12 @@ const TableHead = withStyles(styles, {
{selected && ( - {i18n.t("Selected {{ number }} items", { - number: selected - })} + )}
diff --git a/src/components/Timeline/Timeline.tsx b/src/components/Timeline/Timeline.tsx index 61e5fd72c..2989dae10 100644 --- a/src/components/Timeline/Timeline.tsx +++ b/src/components/Timeline/Timeline.tsx @@ -11,8 +11,7 @@ import { import TextField from "@material-ui/core/TextField"; import PersonIcon from "@material-ui/icons/Person"; import React from "react"; - -import i18n from "../../i18n"; +import { FormattedMessage, useIntl } from "react-intl"; const styles = (theme: Theme) => createStyles({ @@ -70,37 +69,44 @@ export const Timeline = withStyles(styles, { name: "Timeline" })( ); export const TimelineAddNote = withStyles(styles, { name: "TimelineAddNote" })( - ({ classes, message, onChange, onSubmit }: TimelineAddNoteProps) => ( -
- - - - - - {i18n.t("Send", { - context: "add order note" - })} - - ) - }} - variant="standard" - /> - -
- ) + ({ classes, message, onChange, onSubmit }: TimelineAddNoteProps) => { + const intl = useIntl(); + + return ( +
+ + + + + + + + ) + }} + variant="standard" + /> + +
+ ); + } ); Timeline.displayName = "Timeline"; export default Timeline; diff --git a/src/components/VisibilityCard/VisibilityCard.tsx b/src/components/VisibilityCard/VisibilityCard.tsx index 6cb01c853..610e07e49 100644 --- a/src/components/VisibilityCard/VisibilityCard.tsx +++ b/src/components/VisibilityCard/VisibilityCard.tsx @@ -8,12 +8,12 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import ControlledSwitch from "@saleor/components/ControlledSwitch"; import { FormSpacer } from "@saleor/components/FormSpacer"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; -import i18n from "../../i18n"; import { DateContext } from "../Date/DateContext"; const styles = (theme: Theme) => @@ -54,11 +54,17 @@ export const VisibilityCard = withStyles(styles, { disabled, onChange }: VisibilityCardProps) => { + const intl = useIntl(); const localizeDate = useDateLocalize(); const dateNow = React.useContext(DateContext); return ( - +
dateNow - ? i18n.t("will be visible from {{ date }}", { - date: localizeDate(publicationDate) - }) + ? intl.formatMessage( + { + defaultMessage: "will be visible from {date}" + }, + { + date: localizeDate(publicationDate) + } + ) : null : null } @@ -94,7 +114,10 @@ export const VisibilityCard = withStyles(styles, { = ({ weight }) => - i18n.t("{{ value }} {{ unit }}", { - context: "weight", - ...weight - }); +const Weight: React.StatelessComponent = ({ weight }) => ( + +); + Weight.displayName = "Weight"; export default Weight; diff --git a/src/components/WeightRange/WeightRange.tsx b/src/components/WeightRange/WeightRange.tsx index c7a789527..eae54b19c 100644 --- a/src/components/WeightRange/WeightRange.tsx +++ b/src/components/WeightRange/WeightRange.tsx @@ -1,6 +1,6 @@ import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../i18n"; import { Weight } from "../Weight"; export interface WeightRangeProps { @@ -8,28 +8,32 @@ export interface WeightRangeProps { to?: Weight; } -const WeightRange: React.StatelessComponent = ({ - from, - to -}) => - from && to - ? i18n.t("{{ fromValue }} {{ fromUnit }} - {{ toValue }} {{ toUnit }}", { - context: "weight", +const WeightRange: React.FC = ({ from, to }) => + from && to ? ( + + ) : from && !to ? ( + + ) : !from && to ? ( + + ) : ( + - + ); WeightRange.displayName = "WeightRange"; export default WeightRange; diff --git a/src/configuration/ConfigurationPage.tsx b/src/configuration/ConfigurationPage.tsx index 96bc27649..1b71e1102 100644 --- a/src/configuration/ConfigurationPage.tsx +++ b/src/configuration/ConfigurationPage.tsx @@ -8,12 +8,13 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { useIntl } from "react-intl"; import { IconProps } from "@material-ui/core/Icon"; +import { sectionNames } from "@saleor/intl"; import { User } from "../auth/types/User"; import Container from "../components/Container"; import PageHeader from "../components/PageHeader"; -import i18n from "../i18n"; import { PermissionEnum } from "../types/globalTypes"; export interface MenuItem { @@ -68,7 +69,7 @@ const styles = (theme: Theme) => } }); -export interface ConfigurationPageProps extends WithStyles { +export interface ConfigurationPageProps { menu: MenuItem[]; user: User; onSectionClick: (sectionName: string) => void; @@ -76,35 +77,51 @@ export interface ConfigurationPageProps extends WithStyles { export const ConfigurationPage = withStyles(styles, { name: "ConfigurationPage" -})(({ classes, menu, user, onSectionClick }: ConfigurationPageProps) => ( - - -
- {menu - .filter(menuItem => - user.permissions.map(perm => perm.code).includes(menuItem.permission) - ) - .map((menuItem, menuItemIndex) => ( - onSectionClick(menuItem.url)} - key={menuItemIndex} - > - -
{menuItem.icon}
-
- - {menuItem.title} - - - {menuItem.description} - -
-
-
- ))} -
-
-)); +})( + ({ + classes, + menu, + user, + onSectionClick + }: ConfigurationPageProps & WithStyles) => { + const intl = useIntl(); + + return ( + + +
+ {menu + .filter(menuItem => + user.permissions + .map(perm => perm.code) + .includes(menuItem.permission) + ) + .map((menuItem, menuItemIndex) => ( + onSectionClick(menuItem.url)} + key={menuItemIndex} + > + +
{menuItem.icon}
+
+ + {menuItem.title} + + + {menuItem.description} + +
+
+
+ ))} +
+
+ ); + } +); ConfigurationPage.displayName = "ConfigurationPage"; export default ConfigurationPage; diff --git a/src/configuration/index.tsx b/src/configuration/index.tsx index 5cc3beab8..1c991472a 100644 --- a/src/configuration/index.tsx +++ b/src/configuration/index.tsx @@ -1,10 +1,10 @@ import React from "react"; +import { IntlShape, useIntl } from "react-intl"; import { attributeListUrl } from "@saleor/attributes/urls"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useUser from "@saleor/hooks/useUser"; -import i18n from "@saleor/i18n"; import Navigation from "@saleor/icons/Navigation"; import Pages from "@saleor/icons/Pages"; import ProductTypes from "@saleor/icons/ProductTypes"; @@ -12,6 +12,7 @@ import ShippingMethods from "@saleor/icons/ShippingMethods"; import SiteSettings from "@saleor/icons/SiteSettings"; import StaffMembers from "@saleor/icons/StaffMembers"; import Taxes from "@saleor/icons/Taxes"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { menuListUrl } from "@saleor/navigation/urls"; import { pageListUrl } from "@saleor/pages/urls"; @@ -23,76 +24,103 @@ import { taxSection } from "@saleor/taxes/urls"; import { PermissionEnum } from "@saleor/types/globalTypes"; import ConfigurationPage, { MenuItem } from "./ConfigurationPage"; -export const configurationMenu: MenuItem[] = [ - { - description: i18n.t("Determine attributes used to create product types"), - icon: , - permission: PermissionEnum.MANAGE_PRODUCTS, - title: i18n.t("Attributes"), - url: attributeListUrl() - }, - { - description: i18n.t("Define types of products you sell"), - icon: , - permission: PermissionEnum.MANAGE_PRODUCTS, - title: i18n.t("Product Types"), - url: productTypeListUrl() - }, - { - description: i18n.t("Manage your employees and their permissions"), - icon: , - permission: PermissionEnum.MANAGE_STAFF, - title: i18n.t("Staff Members"), - url: staffListUrl() - }, - { - description: i18n.t("Manage how you ship out orders."), - icon: , - permission: PermissionEnum.MANAGE_SHIPPING, - title: i18n.t("Shipping Methods"), - url: shippingZonesListUrl() - }, - { - description: i18n.t("Manage how your store charges tax"), - icon: , - permission: PermissionEnum.MANAGE_PRODUCTS, - title: i18n.t("Taxes"), - url: taxSection - }, - { - description: i18n.t("Define how users can navigate through your store"), - icon: , - permission: PermissionEnum.MANAGE_MENUS, - title: i18n.t("Navigation"), - url: menuListUrl() - }, - { - description: i18n.t("View and update your site settings"), - icon: , - permission: PermissionEnum.MANAGE_SETTINGS, - title: i18n.t("Site Settings"), - url: siteSettingsUrl() - }, - { - description: i18n.t("Manage and add additional pages"), - icon: , - permission: PermissionEnum.MANAGE_PAGES, - title: i18n.t("Pages"), - url: pageListUrl() - } -]; +export function createConfigurationMenu(intl: IntlShape): MenuItem[] { + return [ + { + description: intl.formatMessage({ + defaultMessage: "Determine attributes used to create product types", + id: "configurationMenuAttributes" + }), + icon: , + permission: PermissionEnum.MANAGE_PRODUCTS, + title: intl.formatMessage(sectionNames.attributes), + url: attributeListUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "Define types of products you sell", + id: "configurationMenuProductTypes" + }), + icon: , + permission: PermissionEnum.MANAGE_PRODUCTS, + title: intl.formatMessage(sectionNames.productTypes), + url: productTypeListUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "Manage your employees and their permissions", + id: "configurationMenuStaff" + }), + icon: , + permission: PermissionEnum.MANAGE_STAFF, + title: intl.formatMessage(sectionNames.staff), + url: staffListUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "Manage how you ship out orders", + id: "configurationMenuShipping" + }), + icon: , + permission: PermissionEnum.MANAGE_SHIPPING, + title: intl.formatMessage(sectionNames.shipping), + url: shippingZonesListUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "Manage how your store charges tax", + id: "configurationMenuTaxes" + }), + icon: , + permission: PermissionEnum.MANAGE_PRODUCTS, + title: intl.formatMessage(sectionNames.taxes), + url: taxSection + }, + { + description: intl.formatMessage({ + defaultMessage: "Define how users can navigate through your store", + id: "configurationMenuNavigation" + }), + icon: , + permission: PermissionEnum.MANAGE_MENUS, + title: intl.formatMessage(sectionNames.navigation), + url: menuListUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "View and update your site settings", + id: "configurationMenuSiteSettings" + }), + icon: , + permission: PermissionEnum.MANAGE_SETTINGS, + title: intl.formatMessage(sectionNames.siteSettings), + url: siteSettingsUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "Manage and add additional pages", + id: "configurationMenuPages" + }), + icon: , + permission: PermissionEnum.MANAGE_PAGES, + title: intl.formatMessage(sectionNames.pages), + url: pageListUrl() + } + ]; +} export const configurationMenuUrl = "/configuration/"; -export const ConfigurationSection: React.StatelessComponent = () => { +export const ConfigurationSection: React.FC = () => { const navigate = useNavigator(); const user = useUser(); + const intl = useIntl(); return ( <> - + user.user)} onSectionClick={navigate} /> diff --git a/src/customers/components/CustomerAddress/CustomerAddress.tsx b/src/customers/components/CustomerAddress/CustomerAddress.tsx index 3cd7fbaec..a6605de6b 100644 --- a/src/customers/components/CustomerAddress/CustomerAddress.tsx +++ b/src/customers/components/CustomerAddress/CustomerAddress.tsx @@ -5,12 +5,13 @@ import CardContent from "@material-ui/core/CardContent"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AddressFormatter from "@saleor/components/AddressFormatter"; import CardMenu from "@saleor/components/CardMenu"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { AddressTypeEnum } from "../../../types/globalTypes"; import { CustomerAddresses_user_addresses } from "../../types/CustomerAddresses"; @@ -51,65 +52,81 @@ const CustomerAddress = withStyles(styles, { name: "CustomerAddress" })( onEdit, onRemove, onSetAsDefault - }: CustomerAddressProps & WithStyles) => ( - - - {i18n.t("Address {{ addressNumber }}", { - addressNumber - })} - - {isDefaultBillingAddress && isDefaultShippingAddress - ? i18n.t("Default Address") - : isDefaultShippingAddress - ? i18n.t("Default Shipping Address") - : isDefaultBillingAddress - ? i18n.t("Default Billing Address") - : null} - - - ) : ( - - ) - } - height="const" - toolbar={ - onSetAsDefault(AddressTypeEnum.SHIPPING) - }, - { - label: i18n.t("Set as default billing address", { - context: "button" - }), - onSelect: () => onSetAsDefault(AddressTypeEnum.BILLING) - } - ]} - /> - } - /> - - - -
- - - - -
-
- ) + }: CustomerAddressProps & WithStyles) => { + const intl = useIntl(); + + return ( + + + + + {isDefaultBillingAddress && isDefaultShippingAddress + ? intl.formatMessage({ + defaultMessage: "Default Address" + }) + : isDefaultShippingAddress + ? intl.formatMessage({ + defaultMessage: "Default Shipping Address" + }) + : isDefaultBillingAddress + ? intl.formatMessage({ + defaultMessage: "Default Billing Address" + }) + : null} + + + ) : ( + + ) + } + height="const" + toolbar={ + onSetAsDefault(AddressTypeEnum.SHIPPING) + }, + { + label: intl.formatMessage({ + defaultMessage: "Set as default billing address", + description: "button" + }), + onSelect: () => onSetAsDefault(AddressTypeEnum.BILLING) + } + ]} + /> + } + /> + + + +
+ + + + +
+
+ ); + } ); CustomerAddress.displayName = "CustomerAddress"; export default CustomerAddress; diff --git a/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx b/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx index 1925f7d8c..530da1de3 100644 --- a/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx +++ b/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx @@ -6,6 +6,7 @@ import DialogTitle from "@material-ui/core/DialogTitle"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage } from "react-intl"; import AddressEdit from "@saleor/components/AddressEdit"; import ConfirmButton, { @@ -13,7 +14,7 @@ import ConfirmButton, { } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import i18n from "@saleor/i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { UserError } from "@saleor/types"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; @@ -97,9 +98,17 @@ const CustomerAddressDialog = withStyles(styles, {})( return ( <> - {variant === "create" - ? i18n.t("Add Address") - : i18n.t("Edit Address")} + {variant === "create" ? ( + + ) : ( + + )} - {i18n.t("Save Address", { context: "button" })} - + + {variant === "create" && } diff --git a/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.tsx b/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.tsx index 16817416a..36d67eeea 100644 --- a/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.tsx +++ b/src/customers/components/CustomerAddressListPage/CustomerAddressListPage.tsx @@ -8,11 +8,11 @@ import { import Typography from "@material-ui/core/Typography"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { AddressTypeEnum } from "../../../types/globalTypes"; import { CustomerAddresses_user } from "../../types/CustomerAddresses"; @@ -62,28 +62,42 @@ const CustomerAddressListPage = withStyles(styles, { onRemove, onSetAsDefault }: CustomerAddressListPageProps & WithStyles) => { + const intl = useIntl(); + const isEmpty = maybe(() => customer.addresses.length) === 0; + const fullName = maybe( + () => [customer.firstName, customer.lastName].join(" "), + "..." + ); + return ( - {i18n.t("Customer Info", { - context: "navigation" - })} + {!isEmpty && ( - i18n.t("{{ firstName }} {{ lastName }} Address Book", { - context: "customer address book", - firstName: customer.firstName, - lastName: customer.lastName - }) + title={intl.formatMessage( + { + defaultMessage: "{fullName}'s Address Book", + description: "customer's address book, header" + }, + { + fullName + } )} > @@ -91,12 +105,10 @@ const CustomerAddressListPage = withStyles(styles, { {isEmpty ? (
- {i18n.t("There is no address to show for this customer")} + - {i18n.t( - "This customer doesn’t have any adresses added to his address book. You can add address using the button below." - )} +
diff --git a/src/customers/components/CustomerAddresses/CustomerAddresses.tsx b/src/customers/components/CustomerAddresses/CustomerAddresses.tsx index 54e1a28bf..500354122 100644 --- a/src/customers/components/CustomerAddresses/CustomerAddresses.tsx +++ b/src/customers/components/CustomerAddresses/CustomerAddresses.tsx @@ -9,11 +9,12 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AddressFormatter from "@saleor/components/AddressFormatter"; import CardTitle from "@saleor/components/CardTitle"; import { Hr } from "@saleor/components/Hr"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe } from "../../../misc"; import { CustomerDetails_user } from "../../types/CustomerDetails"; @@ -37,66 +38,85 @@ const CustomerAddresses = withStyles(styles, { name: "CustomerAddresses" })( customer, disabled, onAddressManageClick - }: CustomerAddressesProps) => ( - - - {i18n.t("Manage", { context: "button" })} - - } - /> - {maybe(() => customer.defaultBillingAddress.id) !== - maybe(() => customer.defaultShippingAddress.id) ? ( - <> - {maybe(() => customer.defaultBillingAddress) !== null && ( - - - {i18n.t("Billing address")} - - customer.defaultBillingAddress)} + }: CustomerAddressesProps) => { + const intl = useIntl(); + + return ( + + + + + } + /> + {maybe(() => customer.defaultBillingAddress.id) !== + maybe(() => customer.defaultShippingAddress.id) ? ( + <> + {maybe(() => customer.defaultBillingAddress) !== null && ( + + + + + customer.defaultBillingAddress)} + /> + + )} + {maybe( + () => + customer.defaultBillingAddress && + customer.defaultShippingAddress + ) &&
} + {maybe(() => customer.defaultShippingAddress) && ( + + + + + customer.defaultShippingAddress)} + /> + + )} + + ) : maybe(() => customer.defaultBillingAddress) === null && + maybe(() => customer.defaultShippingAddress) === null ? ( + + + + + + ) : ( + + + - - )} - {maybe( - () => - customer.defaultBillingAddress && customer.defaultShippingAddress - ) &&
} - {maybe(() => customer.defaultShippingAddress) && ( - - - {i18n.t("Shipping address")} - - customer.defaultShippingAddress)} - /> - - )} - - ) : maybe(() => customer.defaultBillingAddress) === null && - maybe(() => customer.defaultShippingAddress) === null ? ( - - - {i18n.t("This customer has no addresses yet")} - - - ) : ( - - {i18n.t("Address")} - customer.defaultBillingAddress)} - /> - - )} -
- ) + + customer.defaultBillingAddress)} + /> +
+ )} +
+ ); + } ); CustomerAddresses.displayName = "CustomerAddresses"; export default CustomerAddresses; diff --git a/src/customers/components/CustomerCreateAddress/CustomerCreateAddress.tsx b/src/customers/components/CustomerCreateAddress/CustomerCreateAddress.tsx index 9ba4fa0c2..40012bae8 100644 --- a/src/customers/components/CustomerCreateAddress/CustomerCreateAddress.tsx +++ b/src/customers/components/CustomerCreateAddress/CustomerCreateAddress.tsx @@ -3,12 +3,12 @@ import CardContent from "@material-ui/core/CardContent"; import { createStyles, WithStyles, withStyles } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AddressEdit from "@saleor/components/AddressEdit"; import CardTitle from "@saleor/components/CardTitle"; import { FormSpacer } from "@saleor/components/FormSpacer"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; -import i18n from "../../../i18n"; import { FormErrors } from "../../../types"; import { AddressTypeInput } from "../../types"; @@ -40,26 +40,35 @@ const CustomerCreateAddress = withStyles(styles, { errors, onChange, onCountryChange - }: CustomerCreateAddressProps) => ( - - - - - {i18n.t("The primary address of this customer.")} - - - { + const intl = useIntl(); + + return ( + + - - - ) + + + + + + + + + ); + } ); CustomerCreateAddress.displayName = "CustomerCreateAddress"; export default CustomerCreateAddress; diff --git a/src/customers/components/CustomerCreateDetails/CustomerCreateDetails.tsx b/src/customers/components/CustomerCreateDetails/CustomerCreateDetails.tsx index db1ffec62..b64276b28 100644 --- a/src/customers/components/CustomerCreateDetails/CustomerCreateDetails.tsx +++ b/src/customers/components/CustomerCreateDetails/CustomerCreateDetails.tsx @@ -8,9 +8,10 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { FormErrors } from "../../../types"; import { CustomerCreatePageFormData } from "../CustomerCreatePage"; @@ -40,48 +41,57 @@ const CustomerCreateDetails = withStyles(styles, { disabled, errors, onChange - }: CustomerCreateDetailsProps) => ( - - - -
- - - -
-
-
- ) + }: CustomerCreateDetailsProps) => { + const intl = useIntl(); + + return ( + + + +
+ + + +
+
+
+ ); + } ); CustomerCreateDetails.displayName = "CustomerCreateDetails"; export default CustomerCreateDetails; diff --git a/src/customers/components/CustomerCreateNote/CustomerCreateNote.tsx b/src/customers/components/CustomerCreateNote/CustomerCreateNote.tsx index e40d3bd48..3a4e9967c 100644 --- a/src/customers/components/CustomerCreateNote/CustomerCreateNote.tsx +++ b/src/customers/components/CustomerCreateNote/CustomerCreateNote.tsx @@ -3,10 +3,10 @@ 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 CardTitle from "@saleor/components/CardTitle"; import { FormSpacer } from "@saleor/components/FormSpacer"; -import i18n from "../../../i18n"; export interface CustomerCreateNoteProps { data: { @@ -24,27 +24,39 @@ const CustomerCreateNote: React.StatelessComponent = ({ disabled, errors, onChange -}) => ( - - - - - {i18n.t("Enter any extra infotmation regarding this customer.")} - - - { + const intl = useIntl(); + + return ( + + - - -); + + + + + + + + + ); +}; CustomerCreateNote.displayName = "CustomerCreateNote"; export default CustomerCreateNote; diff --git a/src/customers/components/CustomerCreatePage/CustomerCreatePage.tsx b/src/customers/components/CustomerCreatePage/CustomerCreatePage.tsx index a38cc3cbb..c40bb6929 100644 --- a/src/customers/components/CustomerCreatePage/CustomerCreatePage.tsx +++ b/src/customers/components/CustomerCreatePage/CustomerCreatePage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; @@ -8,8 +9,8 @@ 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 { sectionNames } from "@saleor/intl"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; -import i18n from "../../../i18n"; import { UserError } from "../../../types"; import { AddressTypeInput } from "../../types"; import { CustomerCreateData_shop_countries } from "../../types/CustomerCreateData"; @@ -59,6 +60,8 @@ const CustomerCreatePage: React.StatelessComponent = ({ onBack, onSubmit }: CustomerCreatePageProps) => { + const intl = useIntl(); + const [countryDisplayName, setCountryDisplayName] = React.useState(""); const countryChoices = countries.map(country => ({ label: country.country, @@ -81,8 +84,15 @@ const CustomerCreatePage: React.StatelessComponent = ({ return ( - {i18n.t("Customers")} - + + + +
@@ -58,88 +59,99 @@ const CustomerDetails = withStyles(styles, { name: "CustomerDetails" })( disabled, errors, onChange - }: CustomerDetailsProps) => ( - - - {i18n.t("General Information")} - {customer && customer.dateJoined ? ( - - {i18n.t("Customer since: {{ month }} {{ year }}", { - month: moment(customer.dateJoined).format("MMM"), - year: moment(customer.dateJoined).format("YYYY") - })} - - ) : ( - - )} - - } - /> - - { + const intl = useIntl(); + + return ( + + + + {customer && customer.dateJoined ? ( + + + + ) : ( + + )} + + } /> - -
- + + +
+ + +
+ -
- - - - -
-
- ) + + + + + ); + } ); CustomerDetails.displayName = "CustomerDetails"; export default CustomerDetails; diff --git a/src/customers/components/CustomerDetailsPage/CustomerDetailsPage.tsx b/src/customers/components/CustomerDetailsPage/CustomerDetailsPage.tsx index ca41daeeb..b36c7ff54 100644 --- a/src/customers/components/CustomerDetailsPage/CustomerDetailsPage.tsx +++ b/src/customers/components/CustomerDetailsPage/CustomerDetailsPage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; @@ -8,7 +9,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 "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { getUserName, maybe } from "../../../misc"; import { UserError } from "../../../types"; import { CustomerDetails_user } from "../../types/CustomerDetails"; @@ -51,59 +52,67 @@ const CustomerDetailsPage: React.StatelessComponent< onRowClick, onAddressManageClick, onDelete -}: CustomerDetailsPageProps) => ( -
customer.email, ""), - firstName: maybe(() => customer.firstName, ""), - isActive: maybe(() => customer.isActive, false), - lastName: maybe(() => customer.lastName, ""), - note: maybe(() => customer.note, "") - }} - onSubmit={onSubmit} - confirmLeave - > - {({ change, data, errors: formErrors, hasChanged, submit }) => ( - - {i18n.t("Customers")} - - -
- - - customer.orders.edges.map(edge => edge.node))} - onViewAllOrdersClick={onViewAllOrdersClick} - onRowClick={onRowClick} - /> -
-
- - - -
-
- -
- )} -
-); +}: CustomerDetailsPageProps) => { + const intl = useIntl(); + + return ( +
customer.email, ""), + firstName: maybe(() => customer.firstName, ""), + isActive: maybe(() => customer.isActive, false), + lastName: maybe(() => customer.lastName, ""), + note: maybe(() => customer.note, "") + }} + onSubmit={onSubmit} + confirmLeave + > + {({ change, data, errors: formErrors, hasChanged, submit }) => ( + + + {intl.formatMessage(sectionNames.customers)} + + + +
+ + + + customer.orders.edges.map(edge => edge.node) + )} + onViewAllOrdersClick={onViewAllOrdersClick} + onRowClick={onRowClick} + /> +
+
+ + + +
+
+ +
+ )} +
+ ); +}; CustomerDetailsPage.displayName = "CustomerDetailsPage"; export default CustomerDetailsPage; diff --git a/src/customers/components/CustomerList/CustomerList.tsx b/src/customers/components/CustomerList/CustomerList.tsx index 5381f23f6..084825438 100644 --- a/src/customers/components/CustomerList/CustomerList.tsx +++ b/src/customers/components/CustomerList/CustomerList.tsx @@ -11,12 +11,12 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; 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 { getUserName, maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { ListCustomers_customers_edges_node } from "../../types/ListCustomers"; @@ -77,13 +77,13 @@ const CustomerList = withStyles(styles, { name: "CustomerList" })( toolbar={toolbar} > - {i18n.t("Customer Name", { context: "table header" })} + - {i18n.t("Customer e-mail", { context: "table header" })} + - {i18n.t("Orders", { context: "table header" })} + @@ -141,7 +141,7 @@ const CustomerList = withStyles(styles, { name: "CustomerList" })( () => ( - {i18n.t("No customers found")} + ) diff --git a/src/customers/components/CustomerListPage/CustomerListPage.tsx b/src/customers/components/CustomerListPage/CustomerListPage.tsx index e39dad20c..02085d39a 100644 --- a/src/customers/components/CustomerListPage/CustomerListPage.tsx +++ b/src/customers/components/CustomerListPage/CustomerListPage.tsx @@ -1,10 +1,11 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { ListCustomers_customers_edges_node } from "../../types/ListCustomers"; import CustomerList from "../CustomerList/CustomerList"; @@ -18,27 +19,32 @@ const CustomerListPage: React.StatelessComponent = ({ disabled, onAdd, ...customerListProps -}) => ( - - - + + - {i18n.t("Add customer", { - context: "button" - })}{" "} - - - - - -); + {...customerListProps} + /> + + ); +}; CustomerListPage.displayName = "CustomerListPage"; export default CustomerListPage; diff --git a/src/customers/components/CustomerOrders/CustomerOrders.tsx b/src/customers/components/CustomerOrders/CustomerOrders.tsx index f6883ca34..1fc5e0d26 100644 --- a/src/customers/components/CustomerOrders/CustomerOrders.tsx +++ b/src/customers/components/CustomerOrders/CustomerOrders.tsx @@ -7,13 +7,13 @@ import TableCell from "@material-ui/core/TableCell"; import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { DateTime } from "@saleor/components/Date"; import Money from "@saleor/components/Money"; import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; -import i18n from "../../../i18n"; import { maybe, renderCollection, transformPaymentStatus } from "../../../misc"; import { CustomerDetails_user_orders_edges_node } from "../../types/CustomerDetails"; @@ -39,23 +39,31 @@ const CustomerOrders = withStyles(styles, { name: "CustomerOrders" })( onRowClick, onViewAllOrdersClick }: CustomerOrdersProps) => { + const intl = useIntl(); + const orderList = orders ? orders.map(order => ({ ...order, - paymentStatus: transformPaymentStatus(order.paymentStatus) + paymentStatus: transformPaymentStatus(order.paymentStatus, intl) })) : undefined; return ( - {i18n.t("View all orders")} + } /> @@ -63,16 +71,28 @@ const CustomerOrders = withStyles(styles, { name: "CustomerOrders" })( - {i18n.t("No. of Order", { context: "table header" })} + - {i18n.t("Date", { context: "table header" })} + - {i18n.t("Status", { context: "table header" })} + - {i18n.t("Total", { context: "table header" })} + @@ -123,7 +143,9 @@ const CustomerOrders = withStyles(styles, { name: "CustomerOrders" })( ), () => ( - {i18n.t("No orders found")} + + + ) )} diff --git a/src/customers/components/CustomerStats/CustomerStats.tsx b/src/customers/components/CustomerStats/CustomerStats.tsx index 1a2a0b4a6..3cdfdd5b3 100644 --- a/src/customers/components/CustomerStats/CustomerStats.tsx +++ b/src/customers/components/CustomerStats/CustomerStats.tsx @@ -8,12 +8,12 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { DateTime } from "@saleor/components/Date"; import { Hr } from "@saleor/components/Hr"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { CustomerDetails_user } from "../../types/CustomerDetails"; @@ -32,48 +32,60 @@ export interface CustomerStatsProps extends WithStyles { } const CustomerStats = withStyles(styles, { name: "CustomerStats" })( - ({ classes, customer }: CustomerStatsProps) => ( - - - - - {i18n.t("Last login")} - - {maybe( - () => ( - - {customer.lastLogin === null ? ( - i18n.t("-") - ) : ( - - )} - - ), - - )} - -
- - - {i18n.t("Last order")} - - {maybe( - () => ( - - {customer.lastPlacedOrder.edges.length === 0 ? ( - i18n.t("-") - ) : ( - - )} - - ), - - )} - -
- ) + ({ classes, customer }: CustomerStatsProps) => { + const intl = useIntl(); + + return ( + + + + + + + {maybe( + () => ( + + {customer.lastLogin === null ? ( + "-" + ) : ( + + )} + + ), + + )} + +
+ + + + + {maybe( + () => ( + + {customer.lastPlacedOrder.edges.length === 0 ? ( + "-" + ) : ( + + )} + + ), + + )} + +
+ ); + } ); CustomerStats.displayName = "CustomerStats"; export default CustomerStats; diff --git a/src/customers/index.tsx b/src/customers/index.tsx index 7ea77efda..7816ca508 100644 --- a/src/customers/index.tsx +++ b/src/customers/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { customerAddPath, customerAddressesPath, @@ -60,17 +61,21 @@ const CustomerAddressesView: React.StatelessComponent< ); }; -export const CustomerSection: React.StatelessComponent<{}> = () => ( - <> - - - - - - - - -); +export const CustomerSection: React.StatelessComponent<{}> = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + + ); +}; diff --git a/src/customers/views/CustomerAddresses.tsx b/src/customers/views/CustomerAddresses.tsx index 9f72bce6a..da7c30019 100644 --- a/src/customers/views/CustomerAddresses.tsx +++ b/src/customers/views/CustomerAddresses.tsx @@ -1,12 +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 { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import CustomerAddressDialog from "../components/CustomerAddressDialog"; import CustomerAddressListPage from "../components/CustomerAddressListPage"; @@ -40,6 +41,7 @@ const CustomerAddresses: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const closeModal = () => navigate(customerAddressesUrl(id), true); const openModal = (action: CustomerAddressesUrlDialog, addressId?: string) => @@ -49,9 +51,7 @@ const CustomerAddresses: React.FC = ({ if (data.addressSetDefault.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Set address as default", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -66,9 +66,7 @@ const CustomerAddresses: React.FC = ({ if (data.addressUpdate.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Updated address", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -77,9 +75,7 @@ const CustomerAddresses: React.FC = ({ if (data.addressDelete.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Removed address", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -214,7 +210,10 @@ const CustomerAddresses: React.FC = ({ @@ -226,9 +225,7 @@ const CustomerAddresses: React.FC = ({ } > - {i18n.t( - "Are you sure you want to remove this address from users address book?" - )} + diff --git a/src/customers/views/CustomerCreate.tsx b/src/customers/views/CustomerCreate.tsx index 10b5719d0..e0a273f51 100644 --- a/src/customers/views/CustomerCreate.tsx +++ b/src/customers/views/CustomerCreate.tsx @@ -1,9 +1,9 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { maybe } from "../../misc"; import CustomerCreatePage from "../components/CustomerCreatePage"; import { TypedCreateCustomerMutation } from "../mutations"; @@ -14,12 +14,13 @@ import { customerListUrl, customerUrl } from "../urls"; export const CustomerCreate: React.StatelessComponent<{}> = () => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleCreateCustomerSuccess = (data: CreateCustomer) => { if (data.customerCreate.errors.length === 0) { notify({ - text: i18n.t("Customer created", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Customer created" }) }); navigate(customerUrl(data.customerCreate.user.id)); @@ -31,7 +32,12 @@ export const CustomerCreate: React.StatelessComponent<{}> = () => { {(createCustomer, createCustomerOpts) => ( <> - + data.shop.countries, [])} disabled={loading || createCustomerOpts.loading} diff --git a/src/customers/views/CustomerDetails.tsx b/src/customers/views/CustomerDetails.tsx index d1e1b57b5..35bd8e17f 100644 --- a/src/customers/views/CustomerDetails.tsx +++ b/src/customers/views/CustomerDetails.tsx @@ -1,11 +1,12 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { orderListUrl, orderUrl } from "../../orders/urls"; import CustomerDetailsPage from "../components/CustomerDetailsPage/CustomerDetailsPage"; @@ -33,21 +34,20 @@ export const CustomerDetailsView: React.StatelessComponent< > = ({ id, params }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleCustomerUpdateSuccess = (data: UpdateCustomer) => { if (data.customerUpdate.errors.length === 0) { notify({ - text: i18n.t("Customer updated", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; const handleCustomerRemoveSuccess = (data: RemoveCustomer) => { if (data.customerDelete.errors.length === 0) { notify({ - text: i18n.t("Customer removed", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Customer Removed" }) }); navigate(customerListUrl()); @@ -132,26 +132,29 @@ export const CustomerDetailsView: React.StatelessComponent< confirmButtonState={removeTransitionState} onClose={() => navigate(customerUrl(id), true)} onConfirm={() => removeCustomer()} - title={i18n.t("Remove customer", { - context: "modal title" + title={intl.formatMessage({ + defaultMessage: "Delete customer", + description: "dialog header" })} variant="delete" open={params.action === "remove"} > - {{ email }}?", - { - context: "modal content", - email: maybe( - () => customerDetails.data.user.email, - "..." - ) - } - ) - }} - /> + + + {maybe( + () => customerDetails.data.user.email, + "..." + )} + + ) + }} + /> + ); diff --git a/src/customers/views/CustomerList.tsx b/src/customers/views/CustomerList.tsx index b36ed9e2a..0ee6d578b 100644 --- a/src/customers/views/CustomerList.tsx +++ b/src/customers/views/CustomerList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useBulkActions from "@saleor/hooks/useBulkActions"; @@ -11,7 +12,7 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import CustomerListPage from "../components/CustomerListPage"; @@ -41,6 +42,7 @@ export const CustomerList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.CUSTOMER_LIST ); + const intl = useIntl(); const closeModal = () => navigate( @@ -66,7 +68,7 @@ export const CustomerList: React.StatelessComponent = ({ const handleBulkCustomerDelete = (data: BulkRemoveCustomers) => { if (data.customerBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Customers removed") + text: intl.formatMessage(commonMessages.savedChanges) }); reset(); refetch(); @@ -120,7 +122,10 @@ export const CustomerList: React.StatelessComponent = ({ toggleAll={toggleAll} /> params.ids.length > 0) + } onClose={closeModal} confirmButtonState={removeTransitionState} onConfirm={() => @@ -131,21 +136,25 @@ export const CustomerList: React.StatelessComponent = ({ }) } variant="delete" - title={i18n.t("Remove customers")} + title={intl.formatMessage({ + defaultMessage: "Delete customers", + description: "dialog header" + })} > - {{ number }} customers?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} + ) + }} + /> + ); diff --git a/src/discounts/components/DiscountCategories/DiscountCategories.tsx b/src/discounts/components/DiscountCategories/DiscountCategories.tsx index 80189cf00..70eaa1cd9 100644 --- a/src/discounts/components/DiscountCategories/DiscountCategories.tsx +++ b/src/discounts/components/DiscountCategories/DiscountCategories.tsx @@ -14,13 +14,13 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; 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 "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ListActions, ListProps } from "../../../types"; import { SaleDetails_sale } from "../../types/SaleDetails"; @@ -71,105 +71,123 @@ const DiscountCategories = withStyles(styles, { toggleAll, selected, isChecked - }: DiscountCategoriesProps & WithStyles) => ( - - - {i18n.t("Assign categories")} - - } - /> - - sale.categories.edges.map(edge => edge.node))} - toggleAll={toggleAll} - toolbar={toolbar} - > - <> - - {i18n.t("Category name")} - - - {i18n.t("Products")} - - - - - - - - - - - {renderCollection( - maybe(() => sale.categories.edges.map(edge => edge.node)), - category => { - const isSelected = category ? isChecked(category.id) : false; + }: DiscountCategoriesProps & WithStyles) => { + const intl = useIntl(); - return ( - - - toggle(category.id)} - /> - - - {maybe(() => category.name, )} - - - {maybe( - () => category.products.totalCount, - - )} - - - { - event.stopPropagation(); - onCategoryUnassign(category.id); - }} - > - - + return ( + + + + + } + /> +
+ sale.categories.edges.map(edge => edge.node))} + toggleAll={toggleAll} + toolbar={toolbar} + > + <> + + + + + + + + + + + + + + + + {renderCollection( + maybe(() => sale.categories.edges.map(edge => edge.node)), + category => { + const isSelected = category ? isChecked(category.id) : false; + + return ( + + + toggle(category.id)} + /> + + + {maybe( + () => category.name, + + )} + + + {maybe( + () => category.products.totalCount, + + )} + + + { + event.stopPropagation(); + onCategoryUnassign(category.id); + }} + > + + + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No categories found")} - - - ) - )} - -
-
- ) + ) + )} + + +
+ ); + } ); DiscountCategories.displayName = "DiscountCategories"; export default DiscountCategories; diff --git a/src/discounts/components/DiscountCollections/DiscountCollections.tsx b/src/discounts/components/DiscountCollections/DiscountCollections.tsx index f863204db..196b5eefa 100644 --- a/src/discounts/components/DiscountCollections/DiscountCollections.tsx +++ b/src/discounts/components/DiscountCollections/DiscountCollections.tsx @@ -14,13 +14,13 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; 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 "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ListActions, ListProps } from "../../../types"; import { SaleDetails_sale } from "../../types/SaleDetails"; @@ -71,105 +71,122 @@ const DiscountCollections = withStyles(styles, { toggle, toggleAll, toolbar - }: DiscountCollectionsProps & WithStyles) => ( - - - {i18n.t("Assign collections")} - - } - /> - - sale.collections.edges.map(edge => edge.node))} - toggleAll={toggleAll} - toolbar={toolbar} - > - - {i18n.t("Collection name")} - - - {i18n.t("Products")} - - - - - - - - - - {renderCollection( - maybe(() => sale.collections.edges.map(edge => edge.node)), - collection => { - const isSelected = collection ? isChecked(collection.id) : false; - return ( - - - toggle(collection.id)} - /> - - - {maybe( - () => collection.name, - - )} - - - {maybe( - () => collection.products.totalCount, - - )} - - - { - event.stopPropagation(); - onCollectionUnassign(collection.id); - }} - > - - + }: DiscountCollectionsProps & WithStyles) => { + const intl = useIntl(); + + return ( + + + + + } + /> +
+ sale.collections.edges.map(edge => edge.node))} + toggleAll={toggleAll} + toolbar={toolbar} + > + + + + + + + + + + + + + + + {renderCollection( + maybe(() => sale.collections.edges.map(edge => edge.node)), + collection => { + const isSelected = collection + ? isChecked(collection.id) + : false; + return ( + + + toggle(collection.id)} + /> + + + {maybe( + () => collection.name, + + )} + + + {maybe( + () => collection.products.totalCount, + + )} + + + { + event.stopPropagation(); + onCollectionUnassign(collection.id); + }} + > + + + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No collections found")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); DiscountCollections.displayName = "DiscountCollections"; export default DiscountCollections; diff --git a/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.tsx b/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.tsx index 58a650be3..6a4556f54 100644 --- a/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.tsx +++ b/src/discounts/components/DiscountCountrySelectDialog/DiscountCountrySelectDialog.tsx @@ -17,6 +17,7 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import { filter } from "fuzzaldrin"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import ConfirmButton, { @@ -27,7 +28,7 @@ import FormSpacer from "@saleor/components/FormSpacer"; import Hr from "@saleor/components/Hr"; // tslint:disable no-submodule-imports import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; interface FormData { allCountries: boolean; @@ -72,6 +73,8 @@ const DiscountCountrySelectDialog = withStyles(styles, { initial, onConfirm }: DiscountCountrySelectDialogProps & WithStyles) => { + const intl = useIntl(); + const initialForm: FormData = { allCountries: true, countries: initial, @@ -90,23 +93,28 @@ const DiscountCountrySelectDialog = withStyles(styles, { return ( <> - {i18n.t("Assign Countries")} + + + - {i18n.t( - "Choose countries, you want voucher to be limited to, from the list below" - )} + change(event, () => fetch(data.query))} - label={i18n.t("Search Countries", { - context: "country search input label" + label={intl.formatMessage({ + defaultMessage: "Filter Countries", + description: "search box label" })} - placeholder={i18n.t("Search by country name", { - context: "country search input placeholder" + placeholder={intl.formatMessage({ + defaultMessage: "Search by country name", + description: "search box placeholder" })} fullWidth /> @@ -114,9 +122,10 @@ const DiscountCountrySelectDialog = withStyles(styles, {
- {i18n.t("Countries A to Z", { - context: "country selection" - })} + @@ -167,7 +176,7 @@ const DiscountCountrySelectDialog = withStyles(styles, { - {i18n.t("Assign countries", { context: "button" })} + diff --git a/src/discounts/components/DiscountProducts/DiscountProducts.tsx b/src/discounts/components/DiscountProducts/DiscountProducts.tsx index 3910cfad9..a39a1ba4c 100644 --- a/src/discounts/components/DiscountProducts/DiscountProducts.tsx +++ b/src/discounts/components/DiscountProducts/DiscountProducts.tsx @@ -14,6 +14,7 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Checkbox from "@saleor/components/Checkbox"; @@ -24,7 +25,6 @@ import TableCellAvatar, { } from "@saleor/components/TableCellAvatar"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ListActions, ListProps } from "../../../types"; import { SaleDetails_sale } from "../../types/SaleDetails"; @@ -84,126 +84,145 @@ const DiscountProducts = withStyles(styles, { toggle, toggleAll, toolbar - }: SaleProductsProps & WithStyles) => ( - - - {i18n.t("Assign products")} - - } - /> -
- sale.products.edges.map(edge => edge.node))} - toggleAll={toggleAll} - toolbar={toolbar} - > - - - {i18n.t("Product name")} - - - - {i18n.t("Product Type")} - - - {i18n.t("Published")} - - - - - - - - - - {renderCollection( - maybe(() => sale.products.edges.map(edge => edge.node)), - product => { - const isSelected = product ? isChecked(product.id) : false; - return ( - - - toggle(product.id)} - /> - - product.thumbnail.url)} + }: SaleProductsProps & WithStyles) => { + const intl = useIntl(); + + return ( + + + + + } + /> +
+ sale.products.edges.map(edge => edge.node))} + toggleAll={toggleAll} + toolbar={toolbar} + > + + + + + + + + + + + + + + + + + + + + {renderCollection( + maybe(() => sale.products.edges.map(edge => edge.node)), + product => { + const isSelected = product ? isChecked(product.id) : false; + return ( + - {maybe(() => product.name, )} - - - {maybe( - () => product.productType.name, - - )} - - - {product && product.isPublished !== undefined ? ( - + toggle(product.id)} /> - ) : ( - - )} - - - { - event.stopPropagation(); - onProductUnassign(product.id); - }} + + product.thumbnail.url)} > - - + {maybe(() => product.name, )} + + + {maybe( + () => product.productType.name, + + )} + + + {product && product.isPublished !== undefined ? ( + + ) : ( + + )} + + + { + event.stopPropagation(); + onProductUnassign(product.id); + }} + > + + + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No products found")} - - - ) - )} - -
- - ) + ) + )} + + + + ); + } ); DiscountProducts.displayName = "DiscountProducts"; export default DiscountProducts; diff --git a/src/discounts/components/SaleCreatePage/SaleCreatePage.tsx b/src/discounts/components/SaleCreatePage/SaleCreatePage.tsx index 04bff4adb..67577afc6 100644 --- a/src/discounts/components/SaleCreatePage/SaleCreatePage.tsx +++ b/src/discounts/components/SaleCreatePage/SaleCreatePage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -8,7 +9,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 "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { UserError } from "../../../types"; import { SaleType } from "../../../types/globalTypes"; import SaleInfo from "../SaleInfo"; @@ -39,6 +40,8 @@ const SaleCreatePage: React.StatelessComponent = ({ saveButtonBarState, onBack }) => { + const intl = useIntl(); + const initialForm: FormData = { endDate: "", name: "", @@ -50,8 +53,15 @@ const SaleCreatePage: React.StatelessComponent = ({
{({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Sales")} - + + {intl.formatMessage(sectionNames.sales)} + +
= ({ toggle, toggleAll }) => { + const intl = useIntl(); + const initialForm: FormData = { endDate: maybe(() => (sale.endDate ? sale.endDate : ""), ""), name: maybe(() => sale.name, ""), @@ -113,7 +116,9 @@ const SaleDetailsPage: React.StatelessComponent = ({ {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Sales")} + + {intl.formatMessage(sectionNames.sales)} + sale.name)} />
@@ -137,34 +142,55 @@ const SaleDetailsPage: React.StatelessComponent = ({ isActive={activeTab === SaleDetailsPageTab.categories} changeTab={onTabClick} > - {i18n.t("Categories ({{ number }})", { - number: maybe( - () => sale.categories.totalCount.toString(), - "…" - ) - })} + {intl.formatMessage( + { + defaultMessage: "Categories ({quantity})", + description: "number of categories", + id: "saleDetailsPageCategoriesQuantity" + }, + { + quantity: maybe( + () => sale.categories.totalCount.toString(), + "…" + ) + } + )} - {i18n.t("Collections ({{ number }})", { - number: maybe( - () => sale.collections.totalCount.toString(), - "…" - ) - })} + {intl.formatMessage( + { + defaultMessage: "Collections ({quantity})", + description: "number of collections", + id: "saleDetailsPageCollectionsQuantity" + }, + { + quantity: maybe( + () => sale.collections.totalCount.toString(), + "…" + ) + } + )} - {i18n.t("Products ({{ number }})", { - number: maybe( - () => sale.products.totalCount.toString(), - "…" - ) - })} + {intl.formatMessage( + { + defaultMessage: "Products ({quantity})", + description: "number of products", + id: "saleDetailsPageProductsQuantity" + }, + { + quantity: maybe( + () => sale.products.totalCount.toString(), + "…" + ) + } + )} diff --git a/src/discounts/components/SaleInfo/SaleInfo.tsx b/src/discounts/components/SaleInfo/SaleInfo.tsx index 2b7a646ff..676884e4b 100644 --- a/src/discounts/components/SaleInfo/SaleInfo.tsx +++ b/src/discounts/components/SaleInfo/SaleInfo.tsx @@ -8,9 +8,10 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { FormData } from "../SaleDetailsPage"; export interface SaleInfoProps { @@ -40,23 +41,32 @@ const SaleInfo = withStyles(styles, { disabled, errors, onChange - }: SaleInfoProps & WithStyles) => ( - - - - ) => { + const intl = useIntl(); + + return ( + + - - - ) + + + + + ); + } ); SaleInfo.displayName = "SaleInfo"; export default SaleInfo; diff --git a/src/discounts/components/SaleList/SaleList.tsx b/src/discounts/components/SaleList/SaleList.tsx index 54669a3f1..7f07d9d64 100644 --- a/src/discounts/components/SaleList/SaleList.tsx +++ b/src/discounts/components/SaleList/SaleList.tsx @@ -11,6 +11,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import Date from "@saleor/components/Date"; @@ -19,7 +20,6 @@ import Percent from "@saleor/components/Percent"; import Skeleton from "@saleor/components/Skeleton"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { SaleType } from "@saleor/types/globalTypes"; @@ -92,24 +92,22 @@ const SaleList = withStyles(styles, { toolbar={toolbar} > - {i18n.t("Name", { - context: "sale list table header" - })} + - {i18n.t("Starts", { - context: "sale list table header" - })} + - {i18n.t("Ends", { - context: "sale list table header" - })} + - {i18n.t("Value", { - context: "sale list table header" - })} + @@ -193,7 +191,7 @@ const SaleList = withStyles(styles, { () => ( - {i18n.t("No sales found")} + ) diff --git a/src/discounts/components/SaleListPage/SaleListPage.tsx b/src/discounts/components/SaleListPage/SaleListPage.tsx index bf0eca395..88d15f1d3 100644 --- a/src/discounts/components/SaleListPage/SaleListPage.tsx +++ b/src/discounts/components/SaleListPage/SaleListPage.tsx @@ -1,10 +1,11 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { SaleList_sales_edges_node } from "../../types/SaleList"; import SaleList from "../SaleList"; @@ -17,16 +18,22 @@ export interface SaleListPageProps extends PageListProps, ListActions { const SaleListPage: React.StatelessComponent = ({ onAdd, ...listProps -}) => ( - - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + ); +}; SaleListPage.displayName = "SaleListPage"; export default SaleListPage; diff --git a/src/discounts/components/SalePricing/SalePricing.tsx b/src/discounts/components/SalePricing/SalePricing.tsx index 4f5fb3790..ae63b90d3 100644 --- a/src/discounts/components/SalePricing/SalePricing.tsx +++ b/src/discounts/components/SalePricing/SalePricing.tsx @@ -9,11 +9,12 @@ import { 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 CardTitle from "@saleor/components/CardTitle"; import Hr from "@saleor/components/Hr"; import TextFieldWithChoice from "@saleor/components/TextFieldWithChoice"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { FormErrors } from "../../../types"; import { SaleType } from "../../../types/globalTypes"; import { FormData } from "../SaleDetailsPage"; @@ -49,75 +50,89 @@ const SalePricing = withStyles(styles, { disabled, errors, onChange - }: SalePricingProps & WithStyles) => ( - - - - ) => { + const intl = useIntl(); + + return ( + + - -
- - - {i18n.t("Time Frame")} - - - - -
- ) + + + +
+ + + + + + + + + ); + } ); SalePricing.displayName = "SalePricing"; export default SalePricing; diff --git a/src/discounts/components/SaleSummary/SaleSummary.tsx b/src/discounts/components/SaleSummary/SaleSummary.tsx index 939b291c9..f5ad7968c 100644 --- a/src/discounts/components/SaleSummary/SaleSummary.tsx +++ b/src/discounts/components/SaleSummary/SaleSummary.tsx @@ -2,6 +2,7 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; 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"; @@ -11,7 +12,7 @@ import Hr from "@saleor/components/Hr"; import Money from "@saleor/components/Money"; import Percent from "@saleor/components/Percent"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { maybe } from "../../../misc"; import { SaleType } from "../../../types/globalTypes"; import { SaleDetails_sale } from "../../types/SaleDetails"; @@ -24,59 +25,71 @@ export interface SaleSummaryProps { const SaleSummary: React.StatelessComponent = ({ defaultCurrency, sale -}) => ( - - - - {i18n.t("Name")} - - {maybe(() => sale.name, )} - - +}) => { + const intl = useIntl(); - {i18n.t("Value")} - - {maybe( - () => - sale.type === SaleType.FIXED ? ( - - ) : ( - + return ( + + + + + + + + {maybe(() => sale.name, )} + + + + + + + + {maybe( + () => + sale.type === SaleType.FIXED ? ( + + ) : ( + + ), + + )} + + + +
+ + + + + + + {maybe( + () => ( + ), - - )} - + + )} +
+ - -
- - - {i18n.t("Start Date")} - - {maybe( - () => ( - - ), - - )} - - - - {i18n.t("End Date")} - - {maybe( - () => - sale.endDate === null ? "-" : , - - )} - -
-
-); + + + + + {maybe( + () => + sale.endDate === null ? "-" : , + + )} + + + + ); +}; SaleSummary.displayName = "SaleSummary"; export default SaleSummary; diff --git a/src/discounts/components/VoucherCreatePage/VoucherCreatePage.tsx b/src/discounts/components/VoucherCreatePage/VoucherCreatePage.tsx index c04902833..7bb1d3e9b 100644 --- a/src/discounts/components/VoucherCreatePage/VoucherCreatePage.tsx +++ b/src/discounts/components/VoucherCreatePage/VoucherCreatePage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -8,7 +9,6 @@ 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 "../../../i18n"; import { UserError } from "../../../types"; import { DiscountValueTypeEnum, @@ -21,6 +21,7 @@ import VoucherLimits from "../VoucherLimits"; import VoucherRequirements from "../VoucherRequirements"; import VoucherTypes from "../VoucherTypes"; +import { sectionNames } from "@saleor/intl"; import VoucherValue from "../VoucherValue"; export interface FormData { applyOncePerCustomer: boolean; @@ -58,6 +59,8 @@ const VoucherCreatePage: React.StatelessComponent = ({ onBack, onSubmit }) => { + const intl = useIntl(); + const initialForm: FormData = { applyOncePerCustomer: false, applyOncePerOrder: false, @@ -81,8 +84,15 @@ const VoucherCreatePage: React.StatelessComponent = ({ {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Vouchers")} - + + {intl.formatMessage(sectionNames.vouchers)} + +
{ + const intl = useIntl(); + return ( - + @@ -72,7 +83,7 @@ const VoucherDates = ({ helperText={errors.endDate} name={"endDate" as keyof FormData} onChange={onChange} - label={i18n.t("End Date")} + label={intl.formatMessage(commonMessages.endDate)} value={data.endDate} type="date" InputLabelProps={{ @@ -86,7 +97,7 @@ const VoucherDates = ({ helperText={errors.endDate} name={"endTime" as keyof FormData} onChange={onChange} - label={i18n.t("End Hour")} + label={intl.formatMessage(commonMessages.endHour)} value={data.endTime} type="time" InputLabelProps={{ diff --git a/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.tsx b/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.tsx index b8b621a72..780ba974e 100644 --- a/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.tsx +++ b/src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.tsx @@ -1,5 +1,6 @@ import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -12,7 +13,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { Tab, TabContainer } from "@saleor/components/Tab"; import { RequirementsPicker } from "@saleor/discounts/types"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe, splitDateTime } from "../../../misc"; import { ListProps, TabListActions, UserError } from "../../../types"; import { @@ -128,6 +129,8 @@ const VoucherDetailsPage: React.StatelessComponent = ({ collectionListToolbar, productListToolbar }) => { + const intl = useIntl(); + let requirementsPickerInitValue; if (maybe(() => voucher.minAmountSpent.amount) > 0) { requirementsPickerInitValue = RequirementsPicker.ORDER; @@ -166,7 +169,9 @@ const VoucherDetailsPage: React.StatelessComponent = ({ {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Vouchers")} + + {intl.formatMessage(sectionNames.vouchers)} + voucher.code)} />
@@ -204,34 +209,52 @@ const VoucherDetailsPage: React.StatelessComponent = ({ isActive={activeTab === VoucherDetailsPageTab.categories} changeTab={onTabClick} > - {i18n.t("Categories ({{ number }})", { - number: maybe( - () => voucher.categories.totalCount.toString(), - "…" - ) - })} + {intl.formatMessage( + { + defaultMessage: "Categories ({quantity})", + description: "number of categories" + }, + { + quantity: maybe( + () => voucher.categories.totalCount.toString(), + "…" + ) + } + )} - {i18n.t("Collections ({{ number }})", { - number: maybe( - () => voucher.collections.totalCount.toString(), - "…" - ) - })} + {intl.formatMessage( + { + defaultMessage: "Collections ({quantity})", + description: "number of collections" + }, + { + quantity: maybe( + () => voucher.collections.totalCount.toString(), + "…" + ) + } + )} - {i18n.t("Products ({{ number }})", { - number: maybe( - () => voucher.products.totalCount.toString(), - "…" - ) - })} + {intl.formatMessage( + { + defaultMessage: "Products ({quantity})", + description: "number of products" + }, + { + quantity: maybe( + () => voucher.products.totalCount.toString(), + "…" + ) + } + )} @@ -291,12 +314,17 @@ const VoucherDetailsPage: React.StatelessComponent = ({ voucher.countries)} disabled={disabled} - emptyText={i18n.t("Voucher applies to all countries")} + emptyText={intl.formatMessage({ + defaultMessage: "Voucher applies to all countries" + })} title={ <> - {i18n.t("Countries")} + {intl.formatMessage({ + defaultMessage: "Countries", + description: "voucher country range" + })} - {i18n.t("Vouchers limited to these countries")} + } diff --git a/src/discounts/components/VoucherInfo/VoucherInfo.tsx b/src/discounts/components/VoucherInfo/VoucherInfo.tsx index 6b93e08ae..0251afac7 100644 --- a/src/discounts/components/VoucherInfo/VoucherInfo.tsx +++ b/src/discounts/components/VoucherInfo/VoucherInfo.tsx @@ -2,10 +2,11 @@ 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 Button from "@material-ui/core/Button"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { generateCode } from "../../../misc"; import { FormErrors } from "../../../types"; import { FormData } from "../VoucherDetailsPage"; @@ -25,6 +26,8 @@ const VoucherInfo = ({ variant, onChange }: VoucherInfoProps) => { + const intl = useIntl(); + const onGenerateCode = () => onChange({ target: { @@ -36,11 +39,14 @@ const VoucherInfo = ({ return ( - {i18n.t("Generate Code")} + ) } @@ -52,7 +58,9 @@ const VoucherInfo = ({ fullWidth helperText={errors.code} name={"code" as keyof FormData} - label={i18n.t("Discount Code")} + label={intl.formatMessage({ + defaultMessage: "Discount Code" + })} value={data.code} onChange={onChange} /> diff --git a/src/discounts/components/VoucherLimits/VoucherLimits.tsx b/src/discounts/components/VoucherLimits/VoucherLimits.tsx index 224c8e360..995e3da57 100644 --- a/src/discounts/components/VoucherLimits/VoucherLimits.tsx +++ b/src/discounts/components/VoucherLimits/VoucherLimits.tsx @@ -2,10 +2,10 @@ 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 { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox"; -import i18n from "../../../i18n"; import { FormErrors } from "../../../types"; import { FormData } from "../VoucherDetailsPage"; @@ -23,15 +23,23 @@ const VoucherLimits = ({ errors, onChange }: VoucherLimitsProps) => { + const intl = useIntl(); + return ( - + @@ -40,7 +48,10 @@ const VoucherLimits = ({ disabled={disabled} error={!!errors.usageLimit} helperText={errors.usageLimit} - label={i18n.t("Limit of Uses")} + label={intl.formatMessage({ + defaultMessage: "Limit of Uses", + description: "voucher" + })} name={"usageLimit" as keyof FormData} value={data.usageLimit} onChange={onChange} @@ -53,7 +64,10 @@ const VoucherLimits = ({ )} diff --git a/src/discounts/components/VoucherList/VoucherList.tsx b/src/discounts/components/VoucherList/VoucherList.tsx index 0c8dda994..5c30a56c1 100644 --- a/src/discounts/components/VoucherList/VoucherList.tsx +++ b/src/discounts/components/VoucherList/VoucherList.tsx @@ -11,6 +11,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import Date from "@saleor/components/Date"; @@ -19,7 +20,6 @@ import Percent from "@saleor/components/Percent"; import Skeleton from "@saleor/components/Skeleton"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { DiscountValueTypeEnum } from "@saleor/types/globalTypes"; @@ -107,34 +107,40 @@ const VoucherList = withStyles(styles, { toolbar={toolbar} > - {i18n.t("Code", { - context: "voucher list table header" - })} + - {i18n.t("Min. Spent", { - context: "voucher list table header" - })} + - {i18n.t("Starts", { - context: "voucher list table header" - })} + - {i18n.t("Ends", { - context: "voucher list table header" - })} + - {i18n.t("Value", { - context: "voucher list table header" - })} + - {i18n.t("Uses", { - context: "voucher list table header" - })} + @@ -239,7 +245,7 @@ const VoucherList = withStyles(styles, { () => ( - {i18n.t("No vouchers found")} + ) diff --git a/src/discounts/components/VoucherListPage/VoucherListPage.tsx b/src/discounts/components/VoucherListPage/VoucherListPage.tsx index f8b75c59a..6b37bc62c 100644 --- a/src/discounts/components/VoucherListPage/VoucherListPage.tsx +++ b/src/discounts/components/VoucherListPage/VoucherListPage.tsx @@ -1,10 +1,11 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { VoucherList_vouchers_edges_node } from "../../types/VoucherList"; import VoucherList from "../VoucherList"; @@ -30,31 +31,35 @@ const VoucherListPage: React.StatelessComponent = ({ toggle, toggleAll, toolbar -}) => ( - - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + ); +}; VoucherListPage.displayName = "VoucherListPage"; export default VoucherListPage; diff --git a/src/discounts/components/VoucherRequirements/VoucherRequirements.tsx b/src/discounts/components/VoucherRequirements/VoucherRequirements.tsx index 4ff9a8aa3..ee9e0b50b 100644 --- a/src/discounts/components/VoucherRequirements/VoucherRequirements.tsx +++ b/src/discounts/components/VoucherRequirements/VoucherRequirements.tsx @@ -2,12 +2,12 @@ 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 { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { FormSpacer } from "@saleor/components/FormSpacer"; import RadioGroupField from "@saleor/components/RadioGroupField"; import { RequirementsPicker } from "@saleor/discounts/types"; -import i18n from "@saleor/i18n"; import { FormErrors } from "@saleor/types"; import { FormData } from "../VoucherDetailsPage"; @@ -25,24 +25,43 @@ const VoucherRequirements = ({ errors, onChange }: VoucherRequirementsProps) => { + const intl = useIntl(); + + const minimalOrderValueText = intl.formatMessage({ + defaultMessage: "Minimal order value", + description: "voucher requirement" + }); + const minimalQuantityText = intl.formatMessage({ + defaultMessage: "Minimum quantity of items", + description: "voucher requirement" + }); + const requirementsPickerChoices = [ { - label: i18n.t("None"), + label: intl.formatMessage({ + defaultMessage: "None", + description: "voucher has no requirements" + }), value: RequirementsPicker.NONE }, { - label: i18n.t("Minimal order value"), + label: minimalOrderValueText, value: RequirementsPicker.ORDER }, { - label: i18n.t("Minimum quantity of items"), + label: minimalQuantityText, value: RequirementsPicker.ITEM } ]; return ( - + = ({ defaultCurrency, voucher }) => { - const translatedVoucherTypes = translateVoucherTypes(); + const intl = useIntl(); + + const translatedVoucherTypes = translateVoucherTypes(intl); return ( - + - {i18n.t("Code")} + + + {maybe(() => voucher.code, )} - {i18n.t("Applies to")} + + + {maybe( () => translatedVoucherTypes[voucher.type], @@ -47,7 +54,12 @@ const VoucherSummary: React.StatelessComponent = ({ - {i18n.t("Value")} + + + {maybe( () => @@ -69,7 +81,9 @@ const VoucherSummary: React.StatelessComponent = ({
- {i18n.t("Start Date")} + + {intl.formatMessage(commonMessages.startDate)} + {maybe( () => ( @@ -80,7 +94,9 @@ const VoucherSummary: React.StatelessComponent = ({ - {i18n.t("End Date")} + + {intl.formatMessage(commonMessages.endDate)} + {maybe( () => @@ -97,7 +113,12 @@ const VoucherSummary: React.StatelessComponent = ({
- {i18n.t("Min. Order Value")} + + + {maybe( () => @@ -111,7 +132,12 @@ const VoucherSummary: React.StatelessComponent = ({ - {i18n.t("Usage Limit")} + + + {maybe( () => (voucher.usageLimit === null ? "-" : voucher.usageLimit), diff --git a/src/discounts/components/VoucherTypes/VoucherTypes.tsx b/src/discounts/components/VoucherTypes/VoucherTypes.tsx index 65074806e..8108ecdb4 100644 --- a/src/discounts/components/VoucherTypes/VoucherTypes.tsx +++ b/src/discounts/components/VoucherTypes/VoucherTypes.tsx @@ -1,11 +1,11 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Grid from "@saleor/components/Grid"; import RadioGroupField from "@saleor/components/RadioGroupField"; -import i18n from "../../../i18n"; import { FormErrors } from "../../../types"; import { DiscountValueTypeEnum } from "../../../types/globalTypes"; import { FormData } from "../VoucherDetailsPage"; @@ -23,24 +23,40 @@ const VoucherTypes = ({ errors, onChange }: VoucherTypesProps) => { + const intl = useIntl(); + const voucherTypeChoices = [ { - label: i18n.t("Fixed Amount"), + label: intl.formatMessage({ + defaultMessage: "Fixed Amount", + description: "voucher discount type" + }), value: DiscountValueTypeEnum.FIXED }, { - label: i18n.t("Percentage"), + label: intl.formatMessage({ + defaultMessage: "Percentage", + description: "voucher discount type" + }), value: DiscountValueTypeEnum.PERCENTAGE }, { - label: i18n.t("Free Shipping"), + label: intl.formatMessage({ + defaultMessage: "Free Shipping", + description: "voucher discount type" + }), value: "SHIPPING" } ]; return ( - + { - const translatedVoucherTypes = translateVoucherTypes(); + const intl = useIntl(); + + const translatedVoucherTypes = translateVoucherTypes(intl); const voucherTypeChoices = Object.values(VoucherType).map(type => ({ label: translatedVoucherTypes[type], value: type @@ -45,7 +47,12 @@ const VoucherValue = ({ return ( - + - {i18n.t("Only once per order", { - context: "voucher application" - })} + - {i18n.t( - "If this option is disabled, discount will be counted for every eligible product" - )} + } diff --git a/src/discounts/index.tsx b/src/discounts/index.tsx index 81d336ff4..22c95c9bd 100644 --- a/src/discounts/index.tsx +++ b/src/discounts/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { saleDetailsPageTab } from "./components/SaleDetailsPage"; import { voucherDetailsPageTab } from "./components/VoucherDetailsPage"; import { @@ -73,17 +74,21 @@ const VoucherDetailsView: React.StatelessComponent< ); }; -export const DiscountSection: React.StatelessComponent<{}> = () => ( - <> - - - - - - - - - - -); +export const DiscountSection: React.StatelessComponent<{}> = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + + + + ); +}; export default DiscountSection; diff --git a/src/discounts/translations.ts b/src/discounts/translations.ts index 5d1b91f4e..323b45af1 100644 --- a/src/discounts/translations.ts +++ b/src/discounts/translations.ts @@ -1,8 +1,24 @@ -import i18n from "../i18n"; +import { defineMessages, IntlShape } from "react-intl"; + import { VoucherTypeEnum } from "../types/globalTypes"; -export const translateVoucherTypes = () => ({ - [VoucherTypeEnum.SHIPPING]: i18n.t("Shipment"), - [VoucherTypeEnum.ENTIRE_ORDER]: i18n.t("Entire order"), - [VoucherTypeEnum.SPECIFIC_PRODUCT]: i18n.t("Specific Products") +const messages = defineMessages({ + order: { + defaultMessage: "Entire order", + 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) }); diff --git a/src/discounts/views/SaleCreate.tsx b/src/discounts/views/SaleCreate.tsx index 445a07bbc..ec9e40e61 100644 --- a/src/discounts/views/SaleCreate.tsx +++ b/src/discounts/views/SaleCreate.tsx @@ -1,10 +1,11 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { sectionNames } from "@saleor/intl"; import { decimal, getMutationState, maybe } from "../../misc"; import { DiscountValueTypeEnum, SaleType } from "../../types/globalTypes"; import SaleCreatePage from "../components/SaleCreatePage"; @@ -22,12 +23,13 @@ export const SaleDetails: React.StatelessComponent = () => { const navigate = useNavigator(); const pushMessage = useNotifier(); const shop = useShop(); + const intl = useIntl(); const handleSaleCreate = (data: SaleCreate) => { if (data.saleCreate.errors.length === 0) { pushMessage({ - text: i18n.t("Successfully created sale", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Successfully created sale" }) }); navigate(saleUrl(data.saleCreate.sale.id), true); @@ -45,7 +47,7 @@ export const SaleDetails: React.StatelessComponent = () => { return ( <> - + shop.defaultCurrency)} disabled={saleCreateOpts.loading} diff --git a/src/discounts/views/SaleDetails.tsx b/src/discounts/views/SaleDetails.tsx index d74c74531..63d677479 100644 --- a/src/discounts/views/SaleDetails.tsx +++ b/src/discounts/views/SaleDetails.tsx @@ -1,6 +1,7 @@ import Button from "@material-ui/core/Button"; import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog"; @@ -14,13 +15,13 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { categoryUrl } from "../../categories/urls"; import { collectionUrl } from "../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; import SearchCategories from "../../containers/SearchCategories"; import SearchCollections from "../../containers/SearchCollections"; import SearchProducts from "../../containers/SearchProducts"; -import i18n from "../../i18n"; import { decimal, getMutationState, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { DiscountValueTypeEnum, SaleType } from "../../types/globalTypes"; @@ -67,6 +68,7 @@ export const SaleDetails: React.StatelessComponent = ({ const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); + const intl = useIntl(); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: SaleDetailsPageTab) => { @@ -81,8 +83,8 @@ export const SaleDetails: React.StatelessComponent = ({ const handleSaleDelete = (data: SaleDelete) => { if (data.saleDelete.errors.length === 0) { notify({ - text: i18n.t("Removed sale", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Removed sale" }) }); navigate(saleListUrl(), true); @@ -92,9 +94,7 @@ export const SaleDetails: React.StatelessComponent = ({ const handleSaleUpdate = (data: SaleUpdate) => { if (data.saleUpdate.errors.length === 0) { notify({ - text: i18n.t("Updated sale", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -131,6 +131,8 @@ export const SaleDetails: React.StatelessComponent = ({ } }; + const canOpenBulkActionDialog = maybe(() => params.ids.length > 0); + return ( {(saleCataloguesRemove, saleCataloguesRemoveOpts) => ( @@ -222,7 +224,9 @@ export const SaleDetails: React.StatelessComponent = ({ return ( <> - + shop.defaultCurrency @@ -295,7 +299,11 @@ export const SaleDetails: React.StatelessComponent = ({ openModal("unassign-category", listElements) } > - {i18n.t("Unassign")} + } collectionListToolbar={ @@ -308,7 +316,11 @@ export const SaleDetails: React.StatelessComponent = ({ ) } > - {i18n.t("Unassign")} + } productListToolbar={ @@ -318,7 +330,11 @@ export const SaleDetails: React.StatelessComponent = ({ openModal("unassign-product", listElements) } > - {i18n.t("Unassign")} + } isChecked={isSelected} @@ -437,77 +453,111 @@ export const SaleDetails: React.StatelessComponent = ({ )} handleCategoriesUnassign(params.ids) } > - {{ saleName }} categories?", - { - saleName: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} handleCollectionsUnassign(params.ids) } > - {{ saleName }} collections?", - { - saleName: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} handleProductsUnassign(params.ids) } > - {{ saleName }} products?", - { - saleName: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} = ({ }) } > - {{ saleName }}?", - { - saleName: maybe( - () => data.sale.name, - "..." - ) - } - ) - }} - /> + + + {maybe(() => data.sale.name, "...")} + + ) + }} + /> + ); diff --git a/src/discounts/views/SaleList.tsx b/src/discounts/views/SaleList.tsx index c159bf502..319b908dc 100644 --- a/src/discounts/views/SaleList.tsx +++ b/src/discounts/views/SaleList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { WindowTitle } from "@saleor/components/WindowTitle"; @@ -13,7 +14,7 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; -import i18n from "@saleor/i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import SaleListPage from "../components/SaleListPage"; @@ -44,10 +45,12 @@ export const SaleList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.SALES_LIST ); + const intl = useIntl(); const closeModal = () => navigate(saleListUrl(), true); const paginationState = createPaginationState(settings.rowNumber, params); + const canOpenBulkActionDialog = maybe(() => params.ids.length > 0); return ( @@ -61,7 +64,7 @@ export const SaleList: React.StatelessComponent = ({ const handleSaleBulkDelete = (data: SaleBulkDelete) => { if (data.saleBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed sales") + text: intl.formatMessage(commonMessages.savedChanges) }); reset(); closeModal(); @@ -86,7 +89,7 @@ export const SaleList: React.StatelessComponent = ({ return ( <> - + shop.defaultCurrency)} sales={maybe(() => data.sales.edges.map(edge => edge.node))} @@ -122,23 +125,30 @@ export const SaleList: React.StatelessComponent = ({ confirmButtonState={bulkRemoveTransitionState} onClose={closeModal} onConfirm={onSaleBulkDelete} - open={params.action === "remove"} - title={i18n.t("Remove Sales")} + open={params.action === "remove" && canOpenBulkActionDialog} + title={intl.formatMessage({ + defaultMessage: "Delete Sales", + description: "dialog header" + })} variant="delete" > - {{ number }} sales?", - { - number: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} ); diff --git a/src/discounts/views/VoucherCreate.tsx b/src/discounts/views/VoucherCreate.tsx index cc4a7bc33..5d55c6273 100644 --- a/src/discounts/views/VoucherCreate.tsx +++ b/src/discounts/views/VoucherCreate.tsx @@ -1,10 +1,11 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { sectionNames } from "@saleor/intl"; import { decimal, getMutationState, joinDateTime, maybe } from "../../misc"; import { DiscountValueTypeEnum, @@ -20,12 +21,13 @@ export const VoucherDetails: React.StatelessComponent = () => { const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const handleVoucherCreate = (data: VoucherCreate) => { if (data.voucherCreate.errors.length === 0) { notify({ - text: i18n.t("Successfully created voucher", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Successfully created voucher" }) }); navigate(voucherUrl(data.voucherCreate.voucher.id), true); @@ -43,7 +45,7 @@ export const VoucherDetails: React.StatelessComponent = () => { return ( <> - + shop.defaultCurrency)} disabled={voucherCreateOpts.loading} diff --git a/src/discounts/views/VoucherDetails.tsx b/src/discounts/views/VoucherDetails.tsx index c7f90799e..9584f07de 100644 --- a/src/discounts/views/VoucherDetails.tsx +++ b/src/discounts/views/VoucherDetails.tsx @@ -1,6 +1,7 @@ import Button from "@material-ui/core/Button"; import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog"; @@ -14,13 +15,13 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { categoryUrl } from "../../categories/urls"; import { collectionUrl } from "../../collections/urls"; import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config"; import SearchCategories from "../../containers/SearchCategories"; import SearchCollections from "../../containers/SearchCollections"; import SearchProducts from "../../containers/SearchProducts"; -import i18n from "../../i18n"; import { decimal, getMutationState, joinDateTime, maybe } from "../../misc"; import { productUrl } from "../../products/urls"; import { @@ -66,6 +67,7 @@ export const VoucherDetails: React.StatelessComponent = ({ const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); + const intl = useIntl(); const paginationState = createPaginationState(PAGINATE_BY, params); const changeTab = (tab: VoucherDetailsPageTab) => { @@ -80,8 +82,8 @@ export const VoucherDetails: React.StatelessComponent = ({ const handleVoucherDelete = (data: VoucherDelete) => { if (data.voucherDelete.errors.length === 0) { notify({ - text: i18n.t("Removed voucher", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Deleted voucher" }) }); navigate(voucherListUrl(), true); @@ -92,9 +94,7 @@ export const VoucherDetails: React.StatelessComponent = ({ if (data.voucherUpdate.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Updated voucher", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -130,6 +130,8 @@ export const VoucherDetails: React.StatelessComponent = ({ } }; + const canOpenBulkActionDialog = maybe(() => params.ids.length > 0); + return ( {(voucherCataloguesRemove, voucherCataloguesRemoveOpts) => ( @@ -225,7 +227,9 @@ export const VoucherDetails: React.StatelessComponent = ({ return ( <> - + shop.defaultCurrency @@ -374,7 +378,11 @@ export const VoucherDetails: React.StatelessComponent = ({ openModal("unassign-category", listElements) } > - {i18n.t("Unassign")} + } collectionListToolbar={ @@ -387,7 +395,11 @@ export const VoucherDetails: React.StatelessComponent = ({ ) } > - {i18n.t("Unassign")} + } productListToolbar={ @@ -397,7 +409,11 @@ export const VoucherDetails: React.StatelessComponent = ({ openModal("unassign-product", listElements) } > - {i18n.t("Unassign")} + } isChecked={isSelected} @@ -539,77 +555,113 @@ export const VoucherDetails: React.StatelessComponent = ({ )} handleCategoriesUnassign(params.ids) } > - {{ saleName }} categories?", - { - saleName: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} handleCollectionsUnassign(params.ids) } > - {{ saleName }} collections?", - { - saleName: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} handleProductsUnassign(params.ids) } > - {{ saleName }} products?", - { - saleName: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} = ({ }) } > - {{ voucherCode }}?", - { - voucherCode: maybe( - () => data.voucher.code, - "..." - ) - } - ) - }} - /> + + + {maybe(() => data.voucher.code, "...")} + + ) + }} + /> + ); diff --git a/src/discounts/views/VoucherList.tsx b/src/discounts/views/VoucherList.tsx index fe47592a2..e70830261 100644 --- a/src/discounts/views/VoucherList.tsx +++ b/src/discounts/views/VoucherList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { WindowTitle } from "@saleor/components/WindowTitle"; @@ -13,7 +14,7 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; -import i18n from "@saleor/i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import VoucherListPage from "../components/VoucherListPage"; @@ -44,10 +45,12 @@ export const VoucherList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.VOUCHER_LIST ); + const intl = useIntl(); const closeModal = () => navigate(voucherListUrl(), true); const paginationState = createPaginationState(settings.rowNumber, params); + const canOpenBulkActionDialog = maybe(() => params.ids.length > 0); return ( @@ -61,7 +64,7 @@ export const VoucherList: React.StatelessComponent = ({ const handleVoucherBulkDelete = (data: VoucherBulkDelete) => { if (data.voucherBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed vouchers") + text: intl.formatMessage(commonMessages.savedChanges) }); reset(); closeModal(); @@ -85,7 +88,9 @@ export const VoucherList: React.StatelessComponent = ({ }); return ( <> - + shop.defaultCurrency)} settings={settings} @@ -123,23 +128,30 @@ export const VoucherList: React.StatelessComponent = ({ confirmButtonState={bulkRemoveTransitionState} onClose={closeModal} onConfirm={onVoucherBulkDelete} - open={params.action === "remove"} - title={i18n.t("Remove Vouchers")} + open={params.action === "remove" && canOpenBulkActionDialog} + title={intl.formatMessage({ + defaultMessage: "Delete Vouchers", + description: "dialog header" + })} variant="delete" > - {{ number }} vouchers?", - { - number: maybe( - () => params.ids.length.toString(), - "..." + {canOpenBulkActionDialog && ( + + {params.ids.length} ) - } - ) - }} - /> + }} + /> + + )} ); diff --git a/src/home/components/HomeActivityCard/HomeActivityCard.tsx b/src/home/components/HomeActivityCard/HomeActivityCard.tsx index 6062878ed..252ee2317 100644 --- a/src/home/components/HomeActivityCard/HomeActivityCard.tsx +++ b/src/home/components/HomeActivityCard/HomeActivityCard.tsx @@ -5,11 +5,11 @@ import ListItemText from "@material-ui/core/ListItemText"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { DateTime } from "@saleor/components/Date"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { renderCollection } from "../../../misc"; import { Home_activities_edges_node } from "../../types/Home"; import { getActivityMessage } from "./activityMessages"; @@ -25,15 +25,23 @@ const styles = createStyles({ } }); -interface HomeProductListCardProps extends WithStyles { +interface HomeActivityCardProps extends WithStyles { activities: Home_activities_edges_node[]; } -const HomeProductListCard = withStyles(styles, { name: "HomeProductListCard" })( - ({ classes, activities }: HomeProductListCardProps) => { +const HomeActivityCard = withStyles(styles, { name: "HomeActivityCard" })( + ({ classes, activities }: HomeActivityCardProps) => { + const intl = useIntl(); + return ( - + {renderCollection( activities, @@ -42,7 +50,9 @@ const HomeProductListCard = withStyles(styles, { name: "HomeProductListCard" })( {activity ? ( {getActivityMessage(activity)} + + {getActivityMessage(activity, intl)} + } secondary={} /> @@ -59,7 +69,12 @@ const HomeProductListCard = withStyles(styles, { name: "HomeProductListCard" })( {i18n.t("No activities found")}
+ + + } /> @@ -70,5 +85,5 @@ const HomeProductListCard = withStyles(styles, { name: "HomeProductListCard" })( ); } ); -HomeProductListCard.displayName = "HomeProductListCard"; -export default HomeProductListCard; +HomeActivityCard.displayName = "HomeActivityCard"; +export default HomeActivityCard; diff --git a/src/home/components/HomeActivityCard/activityMessages.ts b/src/home/components/HomeActivityCard/activityMessages.ts index b195ccdc2..d89cb350c 100644 --- a/src/home/components/HomeActivityCard/activityMessages.ts +++ b/src/home/components/HomeActivityCard/activityMessages.ts @@ -1,25 +1,38 @@ -import i18n from "../../../i18n"; +import { defineMessages, IntlShape } from "react-intl"; + import { OrderEventsEnum } from "../../../types/globalTypes"; 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) { case OrderEventsEnum.ORDER_FULLY_PAID: - return i18n.t("Order #{{ orderId }} was fully paid", { + return intl.formatMessage(messages.paid, { orderId: activity.orderNumber }); case OrderEventsEnum.PLACED: - return i18n.t("Order #{{ orderId }} was placed", { + return intl.formatMessage(messages.placed, { orderId: activity.orderNumber }); case OrderEventsEnum.PLACED_FROM_DRAFT: - return i18n.t( - "Order #{{ orderId }} was placed from draft by {{ user }}", - { - orderId: activity.orderNumber, - user: activity.user.email - } - ); + return intl.formatMessage(messages.draft, { + orderId: activity.orderNumber, + userEmail: activity.user.email + }); default: return activity.message; } diff --git a/src/home/components/HomeAnalyticsCard/HomeAnalyticsCard.tsx b/src/home/components/HomeAnalyticsCard/HomeAnalyticsCard.tsx index 3d509b5a3..9820f87a6 100644 --- a/src/home/components/HomeAnalyticsCard/HomeAnalyticsCard.tsx +++ b/src/home/components/HomeAnalyticsCard/HomeAnalyticsCard.tsx @@ -9,8 +9,7 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; - -import i18n from "../../../i18n"; +import { FormattedMessage } from "react-intl"; const styles = (theme: Theme) => createStyles({ @@ -74,7 +73,10 @@ const HomeAnalyticsCard = withStyles(styles, { name: "HomeAnalyticsCard" })( variant="caption" color="textSecondary" > - {i18n.t("Today")} +
createStyles({ @@ -32,14 +32,25 @@ const HomeOrdersCard = withStyles(styles, { name: "HomeOrdersCard" })(
{userName ? ( - i18n.t("Hello there, {{userName}}", { userName }) + ) : ( )} {userName ? ( - i18n.t("Here is some information we gathered about your store") + ) : ( )} diff --git a/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx b/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx index cca7c0886..f87dc12c7 100644 --- a/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx +++ b/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx @@ -12,9 +12,9 @@ import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"; import React from "react"; +import { FormattedMessage } from "react-intl"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; const styles = (theme: Theme) => createStyles({ @@ -46,83 +46,104 @@ const HomeNotificationTable = withStyles(styles, { ordersToCapture, ordersToFulfill, productsOutOfStock - }: HomeNotificationTableProps) => { - return ( - - - - - - {ordersToFulfill === undefined ? ( - - ) : ordersToFulfill === 0 ? ( - - {i18n.t("No orders ready to fulfill")} - - ) : ( - {{ amount }} Orders are ready to fulfill", - { amount: ordersToFulfill } - ) + }: HomeNotificationTableProps) => ( + +
+ + + + {ordersToFulfill === undefined ? ( + + ) : ordersToFulfill === 0 ? ( + + + + ) : ( + + {ordersToFulfill} }} /> - )} - - - - - - - - {ordersToCapture === undefined ? ( - - ) : ordersToCapture === 0 ? ( - - {i18n.t("No payments waiting for capture")} - - ) : ( - {{ amount }} Payments to capture", - { amount: ordersToCapture } - ) + + )} + + + + + + + + {ordersToCapture === undefined ? ( + + ) : ordersToCapture === 0 ? ( + + + + ) : ( + + {ordersToCapture} }} /> - )} - - - - - - - - {productsOutOfStock === undefined ? ( - - ) : productsOutOfStock === 0 ? ( - {i18n.t("No products out of stock")} - ) : ( - {{ amount }} Products out of stock", - { amount: productsOutOfStock } - ) + + )} + + + + + + + + {productsOutOfStock === undefined ? ( + + ) : productsOutOfStock === 0 ? ( + + + + ) : ( + + {productsOutOfStock} }} /> - )} - - - - - - -
-
- ); - } +
+ )} + + + + + + + + + ) ); HomeNotificationTable.displayName = "HomeNotificationTable"; export default HomeNotificationTable; diff --git a/src/home/components/HomeProductListCard/HomeProductListCard.tsx b/src/home/components/HomeProductListCard/HomeProductListCard.tsx index a7aaa297b..21e3ad6c9 100644 --- a/src/home/components/HomeProductListCard/HomeProductListCard.tsx +++ b/src/home/components/HomeProductListCard/HomeProductListCard.tsx @@ -12,12 +12,12 @@ import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Money from "@saleor/components/Money"; import Skeleton from "@saleor/components/Skeleton"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { Home_productTopToday_edges_node } from "../../types/Home"; @@ -46,80 +46,103 @@ interface HomeProductListProps extends WithStyles { } export const HomeProductList = withStyles(styles, { name: "HomeProductList" })( - ({ classes, topProducts, onRowClick }: HomeProductListProps) => ( - - - - - {renderCollection( - topProducts, - variant => ( - onRowClick(variant.product.id, variant.id) - : undefined - } - > - variant.product.thumbnail.url)} - avatarProps={classes.avatarProps} - /> + ({ classes, topProducts, onRowClick }: HomeProductListProps) => { + const intl = useIntl(); - - {variant ? ( - <> - - {variant.product.name} - - - {maybe(() => - variant.attributes - .map(attribute => attribute.value.name) - .join(" / ") - )} - - - {i18n.t("{{ordersCount}} Orders", { - ordersCount: variant.quantityOrdered - })} - - - ) : ( - - )} - + return ( + + +
+ + {renderCollection( + topProducts, + variant => ( + onRowClick(variant.product.id, variant.id) + : undefined + } + > + variant.product.thumbnail.url)} + avatarProps={classes.avatarProps} + /> - - - {maybe( - () => ( - - ), + + {variant ? ( + <> + + {variant.product.name} + + + {maybe(() => + variant.attributes + .map(attribute => attribute.value.name) + .join(" / ") + )} + + + + + + ) : ( )} - - - - ), - () => ( - - - {i18n.t("No products found")} - - - ) - )} - -
-
- ) + + + + + {maybe( + () => ( + + ), + + )} + + + + ), + () => ( + + + + + + + + ) + )} + + + + ); + } ); HomeProductList.displayName = "HomeProductList"; diff --git a/src/home/components/HomeScreen.tsx b/src/home/components/HomeScreen.tsx index 06a801b2c..c78e9236a 100644 --- a/src/home/components/HomeScreen.tsx +++ b/src/home/components/HomeScreen.tsx @@ -2,11 +2,11 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../i18n"; interface HomeScreenProps { user: { @@ -16,25 +16,44 @@ interface HomeScreenProps { export const HomeScreen: React.StatelessComponent = ({ user -}) => ( - - - - - - - {i18n.t( - "The new dashboard and the GraphQL API are preview-quality software." - )} - - - {i18n.t( - "The GraphQL API is beta quality. It is not fully optimized and some mutations or queries may be missing." - )} - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/src/i18n.ts b/src/i18n.ts deleted file mode 100644 index 91d59c28c..000000000 --- a/src/i18n.ts +++ /dev/null @@ -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; diff --git a/src/index.tsx b/src/index.tsx index 63110ff2e..48e1bb36a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,6 +8,7 @@ import { createUploadLink } from "apollo-upload-client"; import React from "react"; import { ApolloProvider } from "react-apollo"; import { render } from "react-dom"; +import { useIntl } from "react-intl"; import { BrowserRouter, Route, Switch } from "react-router-dom"; import AttributeSection from "./attributes"; @@ -28,11 +29,11 @@ import { ShopProvider } from "./components/Shop"; import ThemeProvider from "./components/Theme"; import { WindowTitle } from "./components/WindowTitle"; import { API_URI, APP_MOUNT_URI } from "./config"; -import ConfigurationSection, { configurationMenu } from "./configuration"; +import ConfigurationSection, { createConfigurationMenu } from "./configuration"; import { CustomerSection } from "./customers"; import DiscountSection from "./discounts"; import HomePage from "./home"; -import i18n from "./i18n"; +import { commonMessages } from "./intl"; import NavigationSection from "./navigation"; import { navigationSection } from "./navigation/urls"; import { NotFound } from "./NotFound"; @@ -116,113 +117,7 @@ const App: React.FC = () => { - - - {({ - hasToken, - isAuthenticated, - tokenAuthLoading, - tokenVerifyLoading, - user - }) => { - return isAuthenticated && - !tokenAuthLoading && - !tokenVerifyLoading ? ( - - - - - - - - - - - - - - - - - - {configurationMenu.filter(menuItem => - hasPermission(menuItem.permission, user) - ).length > 0 && ( - - )} - - - ) : hasToken && tokenVerifyLoading ? ( - - ) : ( - - ); - }} - + @@ -234,4 +129,118 @@ const App: React.FC = () => { ); }; +const Routes: React.FC = () => { + const intl = useIntl(); + + return ( + <> + + + {({ + hasToken, + isAuthenticated, + tokenAuthLoading, + tokenVerifyLoading, + user + }) => + isAuthenticated && !tokenAuthLoading && !tokenVerifyLoading ? ( + + + + + + + + + + + + + + + + + + {createConfigurationMenu(intl).filter(menuItem => + hasPermission(menuItem.permission, user) + ).length > 0 && ( + + )} + + + ) : hasToken && tokenVerifyLoading ? ( + + ) : ( + + ) + } + + + ); +}; + render(, document.querySelector("#dashboard-app")); diff --git a/src/intl.ts b/src/intl.ts new file mode 100644 index 000000000..41d827359 --- /dev/null +++ b/src/intl.ts @@ -0,0 +1,197 @@ +import { defineMessages, IntlShape } from "react-intl"; + +export const commonMessages = defineMessages({ + availability: { + defaultMessage: "Availability" + }, + catalog: { + defaultMessage: "Catalog" + }, + dashboard: { + defaultMessage: "Dashboard" + }, + description: { + defaultMessage: "Description" + }, + discounts: { + defaultMessage: "Discounts" + }, + drafts: { + defaultMessage: "Drafts" + }, + email: { + defaultMessage: "E-mail Address" + }, + endDate: { + defaultMessage: "End Date" + }, + endHour: { + defaultMessage: "End Hour" + }, + firstName: { + defaultMessage: "First Name" + }, + generalInformations: { + defaultMessage: "General Informations" + }, + lastName: { + defaultMessage: "Last Name" + }, + no: { + defaultMessage: "No" + }, + optionalField: { + defaultMessage: "Optional", + description: "field is optional" + }, + properties: { + defaultMessage: "Properties" + }, + savedChanges: { + defaultMessage: "Saved changes" + }, + startDate: { + defaultMessage: "Start Date" + }, + startHour: { + defaultMessage: "Start Hour" + }, + summary: { + defaultMessage: "Summary" + }, + uploadImage: { + defaultMessage: "Upload image", + description: "button" + }, + yes: { + defaultMessage: "Yes" + } +}); + +export const buttonMessages = defineMessages({ + back: { + defaultMessage: "Back", + description: "button" + }, + cancel: { + defaultMessage: "Cancel", + description: "button" + }, + confirm: { + defaultMessage: "Confirm", + description: "button" + }, + delete: { + defaultMessage: "Delete", + description: "button" + }, + edit: { + defaultMessage: "Edit", + description: "button" + }, + manage: { + defaultMessage: "Manage", + description: "button" + }, + remove: { + defaultMessage: "Remove", + description: "button" + }, + save: { + defaultMessage: "Save", + description: "button" + }, + show: { + defaultMessage: "Show", + description: "button" + }, + undo: { + defaultMessage: "Undo", + description: "button" + } +}); + +export const sectionNames = defineMessages({ + attributes: { + defaultMessage: "Attributes", + description: "attributes section name" + }, + categories: { + defaultMessage: "Categories", + description: "categories section name" + }, + collections: { + defaultMessage: "Collections", + description: "collections section name" + }, + configuration: { + defaultMessage: "Configuration", + description: "configuration section name" + }, + customers: { + defaultMessage: "Customers", + description: "customers section name" + }, + draftOrders: { + defaultMessage: "Draft Orders", + description: "draft orders section name" + }, + home: { + defaultMessage: "Home", + description: "home section name" + }, + navigation: { + defaultMessage: "Navigation", + description: "navigation section name" + }, + orders: { + defaultMessage: "Orders", + description: "orders section name" + }, + pages: { + defaultMessage: "Pages", + description: "pages section name" + }, + productTypes: { + defaultMessage: "Product Types", + description: "product types section name" + }, + products: { + defaultMessage: "Products", + description: "products section name" + }, + sales: { + defaultMessage: "Sales", + description: "sales section name" + }, + shipping: { + defaultMessage: "Shipping Methods", + description: "shipping section name" + }, + siteSettings: { + defaultMessage: "Site Settings", + description: "site settings section name" + }, + staff: { + defaultMessage: "Staff Members", + description: "staff section name" + }, + taxes: { + defaultMessage: "Taxes", + description: "taxes section name" + }, + translations: { + defaultMessage: "Translations", + description: "translations section name" + }, + vouchers: { + defaultMessage: "Vouchers", + description: "vouchers section name" + } +}); + +export function translateBoolean(value: boolean, intl: IntlShape): string { + return value + ? intl.formatMessage(commonMessages.yes) + : intl.formatMessage(commonMessages.no); +} diff --git a/src/misc.ts b/src/misc.ts index 1cfbf99cb..122e77459 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -2,10 +2,10 @@ import moment from "moment-timezone"; import { MutationFunction, MutationResult } from "react-apollo"; import urlJoin from "url-join"; +import { defineMessages, IntlShape } from "react-intl"; import { ConfirmButtonTransitionState } from "./components/ConfirmButton/ConfirmButton"; import { APP_MOUNT_URI } from "./config"; import { AddressType } from "./customers/types"; -import i18n from "./i18n"; import { PartialMutationProviderOutput, UserError } from "./types"; import { AuthorizationKeyType, @@ -26,7 +26,7 @@ export type RequireOnlyOne = Pick< > & { [K in Keys]-?: Required> & - Partial, undefined>> + Partial, undefined>>; }[Keys]; export function renderCollection( @@ -57,33 +57,109 @@ export function decimal(value: string | number) { export const removeDoubleSlashes = (url: string) => 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) { case PaymentChargeStatusEnum.PARTIALLY_CHARGED: - return { localized: i18n.t("Partially paid"), status: "error" }; + return { + localized: intl.formatMessage(paymentStatusMessages.partiallyPaid), + status: "error" + }; case PaymentChargeStatusEnum.FULLY_CHARGED: - return { localized: i18n.t("Fully paid"), status: "success" }; + return { + localized: intl.formatMessage(paymentStatusMessages.paid), + status: "success" + }; case PaymentChargeStatusEnum.PARTIALLY_REFUNDED: - return { localized: i18n.t("Partially refunded"), status: "error" }; + return { + localized: intl.formatMessage(paymentStatusMessages.partiallyRefunded), + status: "error" + }; case PaymentChargeStatusEnum.FULLY_REFUNDED: - return { localized: i18n.t("Fully refunded"), status: "success" }; + return { + localized: intl.formatMessage(paymentStatusMessages.refunded), + status: "success" + }; 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) { case OrderStatus.FULFILLED: - return { localized: i18n.t("Fulfilled"), status: "success" }; + return { + localized: intl.formatMessage(orderStatusMessages.fulfilled), + status: "success" + }; case OrderStatus.PARTIALLY_FULFILLED: - return { localized: i18n.t("Partially fulfilled"), status: "neutral" }; + return { + localized: intl.formatMessage(orderStatusMessages.partiallyFulfilled), + status: "neutral" + }; case OrderStatus.UNFULFILLED: - return { localized: i18n.t("Unfulfilled"), status: "error" }; + return { + localized: intl.formatMessage(orderStatusMessages.unfulfilled), + status: "error" + }; case OrderStatus.CANCELED: - return { localized: i18n.t("Cancelled"), status: "error" }; + return { + localized: intl.formatMessage(orderStatusMessages.cancelled), + status: "error" + }; case OrderStatus.DRAFT: - return { localized: i18n.t("Draft"), status: "error" }; + return { + localized: intl.formatMessage(orderStatusMessages.draft), + status: "error" + }; } return { localized: status, @@ -105,44 +181,163 @@ export const transformAddressToForm = (data: AddressType) => ({ streetAddress2: maybe(() => data.streetAddress2, "") }); -export const translatedTaxRates = () => ({ - [TaxRateType.ACCOMMODATION]: i18n.t("Accommodation"), - [TaxRateType.ADMISSION_TO_CULTURAL_EVENTS]: i18n.t( - "Admission to cultural events" - ), - [TaxRateType.ADMISSION_TO_ENTERTAINMENT_EVENTS]: i18n.t( - "Admission to entertainment events" - ), - [TaxRateType.ADMISSION_TO_SPORTING_EVENTS]: i18n.t( - "Admission to sporting events" - ), - [TaxRateType.ADVERTISING]: i18n.t("Advertising"), - [TaxRateType.AGRICULTURAL_SUPPLIES]: i18n.t("Agricultural supplies"), - [TaxRateType.BABY_FOODSTUFFS]: i18n.t("Baby foodstuffs"), - [TaxRateType.BIKES]: i18n.t("Bikes"), - [TaxRateType.BOOKS]: i18n.t("Books"), - [TaxRateType.CHILDRENS_CLOTHING]: i18n.t("Children's clothing"), - [TaxRateType.DOMESTIC_FUEL]: i18n.t("Domestic fuel"), - [TaxRateType.DOMESTIC_SERVICES]: i18n.t("Domestic services"), - [TaxRateType.E_BOOKS]: i18n.t("E-books"), - [TaxRateType.FOODSTUFFS]: i18n.t("Foodstuffs"), - [TaxRateType.HOTELS]: i18n.t("Hotels"), - [TaxRateType.MEDICAL]: i18n.t("Medical"), - [TaxRateType.NEWSPAPERS]: i18n.t("Newspapers"), - [TaxRateType.PASSENGER_TRANSPORT]: i18n.t("Passenger transport"), - [TaxRateType.PHARMACEUTICALS]: i18n.t("Pharmaceuticals"), - [TaxRateType.PROPERTY_RENOVATIONS]: i18n.t("Property renovations"), - [TaxRateType.RESTAURANTS]: i18n.t("Restaurants"), - [TaxRateType.SOCIAL_HOUSING]: i18n.t("Social housing"), - [TaxRateType.STANDARD]: i18n.t("Standard"), - [TaxRateType.WATER]: i18n.t("Water") +const taxRatesMessages = defineMessages({ + accommodation: { + defaultMessage: "Accommodation", + description: "tax rate" + }, + admissionToCulturalEvents: { + defaultMessage: "Admission to cultural events", + description: "tax rate" + }, + admissionToEntertainmentEvents: { + defaultMessage: "Admission to entertainment events", + description: "tax rate" + }, + admissionToSportingEvents: { + defaultMessage: "Admission to sporting events", + description: "tax rate" + }, + advertising: { + defaultMessage: "Advertising", + description: "tax rate" + }, + agriculturalSupplies: { + defaultMessage: "Agricultural supplies", + description: "tax rate" + }, + babyFoodstuffs: { + defaultMessage: "Baby foodstuffs", + description: "tax rate" + }, + bikes: { + 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 = () => ({ - [AuthorizationKeyType.FACEBOOK]: i18n.t("Facebook"), - [AuthorizationKeyType.GOOGLE_OAUTH2]: i18n.t("Google OAuth2") +export const translatedTaxRates = (intl: IntlShape) => ({ + [TaxRateType.ACCOMMODATION]: intl.formatMessage( + 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(exp: () => T): T | undefined; export function maybe(exp: () => T, d: T): T; export function maybe(exp: any, d?: any) { diff --git a/src/mutations.tsx b/src/mutations.tsx index 84bf465b1..f6611b837 100644 --- a/src/mutations.tsx +++ b/src/mutations.tsx @@ -2,9 +2,9 @@ import { ApolloError, MutationUpdaterFn } from "apollo-client"; import { DocumentNode } from "graphql"; import React from "react"; import { Mutation, MutationFunction, MutationResult } from "react-apollo"; +import { useIntl } from "react-intl"; import useNotifier from "./hooks/useNotifier"; -import i18n from "./i18n"; export interface TypedMutationInnerProps { children: ( @@ -23,6 +23,7 @@ export function TypedMutation( ) { return (props: TypedMutationInnerProps) => { const notify = useNotifier(); + const intl = useIntl(); const { children, onCompleted, onError, variables } = props; return ( @@ -30,9 +31,15 @@ export function TypedMutation( mutation={mutation} onCompleted={onCompleted} onError={err => { - const msg = i18n.t("Something went wrong: {{ message }}", { - message: err.message - }); + const msg = intl.formatMessage( + { + defaultMessage: "Something went wrong. {errorMessage}", + description: "error message" + }, + { + errorMessage: err.message + } + ); notify({ text: msg }); if (onError) { onError(err); diff --git a/src/navigation/components/MenuCreateDialog/MenuCreateDialog.tsx b/src/navigation/components/MenuCreateDialog/MenuCreateDialog.tsx index fd06ad788..c244c10ab 100644 --- a/src/navigation/components/MenuCreateDialog/MenuCreateDialog.tsx +++ b/src/navigation/components/MenuCreateDialog/MenuCreateDialog.tsx @@ -5,12 +5,13 @@ 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 i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; export interface MenuCreateDialogFormData { name: string; @@ -34,46 +35,55 @@ const MenuCreateDialog: React.FC = ({ onClose, onConfirm, open -}) => ( - - - {i18n.t("Add Menu", { - context: "create menu modal window title" - })} - - - {({ change, data, errors: formErrors, submit }) => ( - <> - - - - - - - {i18n.t("Create")} - - - - )} - - -); +}) => { + const intl = useIntl(); + + return ( + + + + +
+ {({ change, data, errors: formErrors, submit }) => ( + <> + + + + + + + + + + + )} +
+
+ ); +}; MenuCreateDialog.displayName = "MenuCreateDialog"; export default MenuCreateDialog; diff --git a/src/navigation/components/MenuDetailsPage/MenuDetailsPage.tsx b/src/navigation/components/MenuDetailsPage/MenuDetailsPage.tsx index 6c22f0d0d..e9175ffa0 100644 --- a/src/navigation/components/MenuDetailsPage/MenuDetailsPage.tsx +++ b/src/navigation/components/MenuDetailsPage/MenuDetailsPage.tsx @@ -1,5 +1,6 @@ import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -8,7 +9,7 @@ import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { MenuDetails_menu } from "../../types/MenuDetails"; import { MenuItemType } from "../MenuItemDialog"; @@ -47,6 +48,8 @@ const MenuDetailsPage: React.StatelessComponent = ({ onItemEdit, onSubmit }) => { + const intl = useIntl(); + const initialForm: MenuDetailsFormData = { name: maybe(() => menu.name, "") }; @@ -76,14 +79,19 @@ const MenuDetailsPage: React.StatelessComponent = ({
{({ change, data, hasChanged, submit }) => ( - {i18n.t("Navigation")} + + {intl.formatMessage(sectionNames.navigation)} +
- {i18n.t("Navigation")} + + {intl.formatMessage(sectionNames.navigation)} + - {i18n.t( - "Creating the navigation structure is done by dragging and dropping. Simply create a new menu item and then drag it into its destined place. You can move items inside one another to create a tree structure and drag items up and down to create a hierarchy" - )} +
diff --git a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx index 87c9a0c56..b3d9de48f 100644 --- a/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx +++ b/src/navigation/components/MenuItemDialog/MenuItemDialog.tsx @@ -7,6 +7,7 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import isUrl from "is-url"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AutocompleteSelectMenu from "@saleor/components/AutocompleteSelectMenu"; import ConfirmButton, { @@ -18,7 +19,7 @@ import { SearchCollections_collections_edges_node } from "@saleor/containers/Sea import { SearchPages_pages_edges_node } from "@saleor/containers/SearchPages/types/SearchPages"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import i18n from "@saleor/i18n"; +import { buttonMessages, sectionNames } from "@saleor/intl"; import { UserError } from "@saleor/types"; import { getErrors, getFieldError } from "@saleor/utils/errors"; import { getMenuItemByValue, IMenu } from "@saleor/utils/menu"; @@ -86,6 +87,7 @@ const MenuItemDialog: React.StatelessComponent = ({ collections, pages }) => { + const intl = useIntl(); const errors = useModalDialogErrors(apiErrors, open); const [displayValue, setDisplayValue] = React.useState( initialDisplayValue || "" @@ -121,7 +123,7 @@ const MenuItemDialog: React.StatelessComponent = ({ value: "category:" + category.id })), data: {}, - label: i18n.t("Categories") + label: intl.formatMessage(sectionNames.categories) } ]; } @@ -137,7 +139,7 @@ const MenuItemDialog: React.StatelessComponent = ({ value: "collection:" + collection.id })), data: {}, - label: i18n.t("Collections") + label: intl.formatMessage(sectionNames.collections) } ]; } @@ -153,7 +155,7 @@ const MenuItemDialog: React.StatelessComponent = ({ value: "page:" + page.id })), data: {}, - label: i18n.t("Pages") + label: intl.formatMessage(sectionNames.pages) } ]; } @@ -164,12 +166,12 @@ const MenuItemDialog: React.StatelessComponent = ({ children: [], data: {}, label: ( -
{{ url }}", { - context: "add link to navigation", - url - }) + {url} }} /> ), @@ -218,17 +220,25 @@ const MenuItemDialog: React.StatelessComponent = ({ > {!!initial - ? i18n.t("Edit Item", { - context: "edit menu item" + ? intl.formatMessage({ + defaultMessage: "Edit Item", + description: "edit menu item, header", + id: "menuItemDialogEditItem" }) - : i18n.t("Add Item", { - context: "create new menu item" + : intl.formatMessage({ + defaultMessage: "Add Item", + description: "create new menu item, header", + id: "menuItemDialogAddItem" })} @@ -246,13 +256,20 @@ const MenuItemDialog: React.StatelessComponent = ({ disabled={disabled} onChange={handleSelectChange} name="id" - label={i18n.t("Link")} + label={intl.formatMessage({ + defaultMessage: "Link", + description: "label", + id: "menuItemDialogLinkLabel" + })} displayValue={displayValue} loading={loading} options={options} error={!!idError} helperText={idError} - placeholder={i18n.t("Start typing to begin search...")} + placeholder={intl.formatMessage({ + defaultMessage: "Start typing to begin search...", + id: "menuItemDialogLinkPlaceholder" + })} onInputChange={handleQueryChange} /> {mutationErrors.length > 0 && ( @@ -268,7 +285,7 @@ const MenuItemDialog: React.StatelessComponent = ({ = ({ variant="contained" onClick={handleSubmit} > - {i18n.t("Submit", { context: "button" })} + diff --git a/src/navigation/components/MenuItems/MenuItems.tsx b/src/navigation/components/MenuItems/MenuItems.tsx index ef17ab78a..a35ccb852 100644 --- a/src/navigation/components/MenuItems/MenuItems.tsx +++ b/src/navigation/components/MenuItems/MenuItems.tsx @@ -14,12 +14,13 @@ import DeleteIcon from "@material-ui/icons/Delete"; import EditIcon from "@material-ui/icons/Edit"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import SortableTree, { NodeRendererProps, TreeItem } from "react-sortable-tree"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; import useTheme from "@saleor/hooks/useTheme"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import Draggable from "../../../icons/Draggable"; import { MenuDetails_menu_items } from "../../types/MenuDetails"; import { MenuItemType } from "../MenuItemDialog"; @@ -121,7 +122,10 @@ const Placeholder = withStyles(styles, { })(({ classes }: WithStyles) => ( - {i18n.t("Add new menu item to begin creating menu")} + )); @@ -175,7 +179,7 @@ const Node = withStyles(styles, {
@@ -209,15 +213,20 @@ const MenuItems = withStyles(styles, { name: "MenuItems" })( onItemEdit, onUndo }: MenuItemsProps & WithStyles) => { + const intl = useIntl(); const { isDark } = useTheme(); return ( - {i18n.t("Undo")} + } /> @@ -266,9 +275,11 @@ const MenuItems = withStyles(styles, { name: "MenuItems" })(
diff --git a/src/navigation/components/MenuList/MenuList.tsx b/src/navigation/components/MenuList/MenuList.tsx index 75c89ef23..423efcc0f 100644 --- a/src/navigation/components/MenuList/MenuList.tsx +++ b/src/navigation/components/MenuList/MenuList.tsx @@ -12,13 +12,13 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import IconButtonTableCell from "@saleor/components/IconButtonTableCell"; import Skeleton from "@saleor/components/Skeleton"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { MenuList_menus_edges_node } from "../../types/MenuList"; @@ -76,10 +76,17 @@ const MenuList = withStyles(styles, { name: "MenuList" })( toolbar={toolbar} > - {i18n.t("Menu Title", { context: "object" })} + - {i18n.t("Items", { context: "number of menu items" })} + @@ -140,7 +147,10 @@ const MenuList = withStyles(styles, { name: "MenuList" })( () => ( - {i18n.t("No menus found")} + ) diff --git a/src/navigation/components/MenuListPage/MenuListPage.tsx b/src/navigation/components/MenuListPage/MenuListPage.tsx index 04f0f5926..12728b73f 100644 --- a/src/navigation/components/MenuListPage/MenuListPage.tsx +++ b/src/navigation/components/MenuListPage/MenuListPage.tsx @@ -1,11 +1,12 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { MenuList_menus_edges_node } from "../../types/MenuList"; import MenuList from "../MenuList"; @@ -21,21 +22,31 @@ const MenuListPage: React.StatelessComponent = ({ onAdd, onBack, ...listProps -}) => ( - - {i18n.t("Configuration")} - - - - - -); +}) => { + const intl = useIntl(); + return ( + + + {intl.formatMessage(sectionNames.configuration)} + + + + + + + ); +}; MenuListPage.displayName = "MenuListPage"; export default MenuListPage; diff --git a/src/navigation/components/MenuProperties/MenuProperties.tsx b/src/navigation/components/MenuProperties/MenuProperties.tsx index a0379b149..624840f7d 100644 --- a/src/navigation/components/MenuProperties/MenuProperties.tsx +++ b/src/navigation/components/MenuProperties/MenuProperties.tsx @@ -2,9 +2,10 @@ 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 { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { MenuDetailsFormData } from "../MenuDetailsPage"; export interface MenuPropertiesProps { @@ -17,20 +18,29 @@ const MenuProperties: React.StatelessComponent = ({ data, disabled, onChange -}) => ( - - - - { + const intl = useIntl(); + + return ( + + - - -); + + + + + ); +}; MenuProperties.displayName = "MenuProperties"; export default MenuProperties; diff --git a/src/navigation/views/MenuDetails/index.tsx b/src/navigation/views/MenuDetails/index.tsx index 1bc722399..7f12ba8e3 100644 --- a/src/navigation/views/MenuDetails/index.tsx +++ b/src/navigation/views/MenuDetails/index.tsx @@ -1,5 +1,6 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useNavigator from "@saleor/hooks/useNavigator"; @@ -10,7 +11,6 @@ import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; import SearchCategories from "../../../containers/SearchCategories"; import SearchCollections from "../../../containers/SearchCollections"; import SearchPages from "../../../containers/SearchPages"; -import i18n from "../../../i18n"; import { getMutationState, maybe } from "../../../misc"; import { pageUrl } from "../../../pages/urls"; import MenuDetailsPage, { @@ -58,6 +58,7 @@ interface MenuDetailsProps { const MenuDetails: React.FC = ({ id, params }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const closeModal = () => navigate( @@ -135,13 +136,13 @@ const MenuDetails: React.FC = ({ id, params }) => { return ( - handleDelete(data, navigate, notify) + handleDelete(data, navigate, notify, intl) } > {(menuDelete, menuDeleteOpts) => ( - handleUpdate(data, notify, refetch) + handleUpdate(data, notify, refetch, intl) } > {(menuUpdate, menuUpdateOpts) => { @@ -236,26 +237,38 @@ const MenuDetails: React.FC = ({ id, params }) => { menuDelete({ variables: { id } }) } variant="delete" - title={i18n.t("Remove menu")} + title={intl.formatMessage({ + defaultMessage: "Delete menu", + description: "dialog header", + id: "menuDetailsDeleteMenuHeader" + })} > - {{ name }}?", - { - name: maybe( - () => data.menu.name, - "..." - ) - } - ) - }} - /> + + + {maybe( + () => data.menu.name, + "..." + )} + + ) + }} + /> + - handleItemCreate(data, notify, closeModal) + handleItemCreate( + data, + notify, + closeModal, + intl + ) } > {(menuItemCreate, menuItemCreateOpts) => { @@ -315,7 +328,8 @@ const MenuDetails: React.FC = ({ id, params }) => { data, id, navigate, - notify + notify, + intl ) } > diff --git a/src/navigation/views/MenuDetails/successHandlers.ts b/src/navigation/views/MenuDetails/successHandlers.ts index 995211a6f..1dce13307 100644 --- a/src/navigation/views/MenuDetails/successHandlers.ts +++ b/src/navigation/views/MenuDetails/successHandlers.ts @@ -1,6 +1,8 @@ +import { IntlShape } from "react-intl"; + +import { commonMessages } from "@saleor/intl"; import { UseNavigatorResult } from "../../../hooks/useNavigator"; import { UseNotifierResult } from "../../../hooks/useNotifier"; -import i18n from "../../../i18n"; import { MenuDelete } from "../../types/MenuDelete"; import { MenuItemCreate } from "../../types/MenuItemCreate"; import { MenuItemUpdate } from "../../types/MenuItemUpdate"; @@ -10,14 +12,13 @@ import { menuListUrl, menuUrl } from "../../urls"; export function handleItemCreate( data: MenuItemCreate, notify: UseNotifierResult, - closeModal: () => void + closeModal: () => void, + intl: IntlShape ) { if (data.menuItemCreate.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Created menu item", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } } @@ -26,13 +27,12 @@ export function handleItemUpdate( data: MenuItemUpdate, id: string, navigate: UseNavigatorResult, - notify: UseNotifierResult + notify: UseNotifierResult, + intl: IntlShape ) { if (data.menuItemUpdate.errors.length === 0) { notify({ - text: i18n.t("Updated menu item", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); navigate( menuUrl(id, { @@ -46,13 +46,12 @@ export function handleItemUpdate( export function handleDelete( data: MenuDelete, navigate: UseNavigatorResult, - notify: UseNotifierResult + notify: UseNotifierResult, + intl: IntlShape ) { if (data.menuDelete.errors.length === 0) { notify({ - text: i18n.t("Removed menu", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(menuListUrl(), true); } @@ -61,7 +60,8 @@ export function handleDelete( export function handleUpdate( data: MenuUpdate, notify: UseNotifierResult, - refetch: () => void + refetch: () => void, + intl: IntlShape ) { if ( data.menuItemBulkDelete.errors.length === 0 && @@ -69,9 +69,7 @@ export function handleUpdate( data.menuUpdate.errors.length === 0 ) { notify({ - text: i18n.t("Updated menu", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); refetch(); } diff --git a/src/navigation/views/MenuList.tsx b/src/navigation/views/MenuList.tsx index fbde8d36f..2995e0199 100644 --- a/src/navigation/views/MenuList.tsx +++ b/src/navigation/views/MenuList.tsx @@ -1,6 +1,7 @@ import Button from "@material-ui/core/Button"; import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { configurationMenuUrl } from "@saleor/configuration"; @@ -11,7 +12,7 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; -import i18n from "@saleor/i18n"; +import { buttonMessages, commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import MenuCreateDialog from "../components/MenuCreateDialog"; @@ -40,6 +41,7 @@ const MenuList: React.FC = ({ params }) => { const { updateListSettings, settings } = useListSettings( ListViews.NAVIGATION_LIST ); + const intl = useIntl(); const closeModal = () => navigate( @@ -66,8 +68,9 @@ const MenuList: React.FC = ({ params }) => { const handleCreate = (data: MenuCreate) => { if (data.menuCreate.errors.length === 0) { notify({ - text: i18n.t("Created menu", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Created menu", + id: "menuListCreatedMenu" }) }); navigate(menuUrl(data.menuCreate.menu.id)); @@ -77,9 +80,7 @@ const MenuList: React.FC = ({ params }) => { const handleBulkDelete = (data: MenuBulkDelete) => { if (data.menuBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed menus", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); reset(); @@ -90,8 +91,9 @@ const MenuList: React.FC = ({ params }) => { const handleDelete = (data: MenuDelete) => { if (data.menuDelete.errors.length === 0) { notify({ - text: i18n.t("Removed menu", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Deleted menu", + id: "menuListDeletedMenu" }) }); closeModal(); @@ -172,7 +174,7 @@ const MenuList: React.FC = ({ params }) => { ) } > - {i18n.t("Remove")} + } /> @@ -199,27 +201,33 @@ const MenuList: React.FC = ({ params }) => { }) } variant="delete" - title={i18n.t("Remove menu")} + title={intl.formatMessage({ + defaultMessage: "Delete menu", + description: "dialog header", + id: "menuListDeleteMenuHeader" + })} > - {{ name }}?", - { - name: maybe( - () => - data.menus.edges.find( - edge => edge.node.id === params.id - ).node.name, - "..." - ) - } - ) - }} - /> + + + data.menus.edges.find( + edge => edge.node.id === params.id + ).node.name, + "..." + ) + }} + /> + params.ids.length > 0) + } onClose={closeModal} confirmButtonState={bulkDeleteTransitionState} onConfirm={() => @@ -230,21 +238,35 @@ const MenuList: React.FC = ({ params }) => { }) } variant="delete" - title={i18n.t("Remove menus")} + title={intl.formatMessage({ + defaultMessage: "Delete menus", + description: "dialog header", + id: "menuListDeleteMenusHeader" + })} > - {{ number }} menus?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length.toString(), + "..." + ), + displayQuantity: ( + + {maybe( + () => params.ids.length.toString(), + "..." + )} + + ) + }} + /> + ); diff --git a/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx b/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx index c351178cb..e6468a9bf 100644 --- a/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx +++ b/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx @@ -5,6 +5,7 @@ import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AddressEdit from "@saleor/components/AddressEdit"; import ConfirmButton, { @@ -12,10 +13,10 @@ import ConfirmButton, { } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { buttonMessages } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { AddressTypeInput } from "../../../customers/types"; -import i18n from "../../../i18n"; import { UserError } from "../../../types"; const styles = createStyles({ @@ -52,6 +53,7 @@ const OrderAddressEditDialog = withStyles(styles, { onClose, onConfirm }: OrderAddressEditDialogProps) => { + const intl = useIntl(); const [countryDisplayName, setCountryDisplayName] = useStateFromProps( maybe( () => countries.find(country => address.country === country.code).label @@ -80,8 +82,14 @@ const OrderAddressEditDialog = withStyles(styles, { <> {variant === "billing" - ? i18n.t("Edit billing address", { context: "title" }) - : i18n.t("Edit shipping address", { context: "title" })} + ? intl.formatMessage({ + defaultMessage: "Edit billing address", + description: "dialog header" + }) + : intl.formatMessage({ + defaultMessage: "Edit shipping address", + description: "dialog header" + })} - {i18n.t("Confirm", { context: "button" })} + diff --git a/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx b/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx index 0c25ddeb0..21923f846 100644 --- a/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx +++ b/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx @@ -1,10 +1,10 @@ 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 ControlledCheckbox from "@saleor/components/ControlledCheckbox"; -import i18n from "../../../i18n"; export interface OrderBulkCancelDialogProps { confirmButtonState: ConfirmButtonTransitionState; @@ -17,6 +17,7 @@ export interface OrderBulkCancelDialogProps { const OrderBulkCancelDialog: React.StatelessComponent< OrderBulkCancelDialogProps > = ({ confirmButtonState, numberOfOrders, open, onClose, onConfirm }) => { + const intl = useIntl(); const [restock, setRestock] = React.useState(true); return ( @@ -24,23 +25,31 @@ const OrderBulkCancelDialog: React.StatelessComponent< confirmButtonState={confirmButtonState} open={open} variant="delete" - title={i18n.t("Cancel Orders")} + title={intl.formatMessage({ + defaultMessage: "Cancel Orders", + description: "dialog header" + })} onClose={onClose} onConfirm={() => onConfirm(restock)} > - {{ number }} orders?", - { - number: numberOfOrders - } - ) - }} - /> + + {numberOfOrders} + }} + /> + setRestock(event.target.value)} /> diff --git a/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx b/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx index 51eb429aa..0bc4e8e13 100644 --- a/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx +++ b/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx @@ -11,13 +11,14 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import Form from "@saleor/components/Form"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; export interface FormData { restock: boolean; @@ -50,55 +51,66 @@ const OrderCancelDialog = withStyles(styles, { name: "OrderCancelDialog" })( open, onSubmit, onClose - }: OrderCancelDialogProps) => ( - - - {({ data, change }) => { - return ( - <> - - {i18n.t("Cancel order", { context: "title" })} - - - {{ orderNumber }}?", - { orderNumber } - ) - }} - /> - - - - - - {i18n.t("Cancel order", { context: "button" })} - - - - ); - }} - - - ) + }: OrderCancelDialogProps) => { + const intl = useIntl(); + + return ( + +
+ {({ data, change }) => { + return ( + <> + + + + + + + + + + + + + + + + + ); + }} +
+
+ ); + } ); OrderCancelDialog.displayName = "OrderCancelDialog"; export default OrderCancelDialog; diff --git a/src/orders/components/OrderCustomer/OrderCustomer.tsx b/src/orders/components/OrderCustomer/OrderCustomer.tsx index c2319a911..3f800300c 100644 --- a/src/orders/components/OrderCustomer/OrderCustomer.tsx +++ b/src/orders/components/OrderCustomer/OrderCustomer.tsx @@ -9,6 +9,7 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import ExternalLink from "@saleor/components/ExternalLink"; @@ -18,10 +19,10 @@ import Link from "@saleor/components/Link"; import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField"; import Skeleton from "@saleor/components/Skeleton"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { buttonMessages } from "@saleor/intl"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { SearchCustomers_customers_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers"; import { customerUrl } from "../../../customers/urls"; -import i18n from "../../../i18n"; import { createHref, maybe } from "../../../misc"; import { OrderDetails_order } from "../../types/OrderDetails"; @@ -74,6 +75,8 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( onProfileView, onShippingAddressEdit }: OrderCustomerProps) => { + const intl = useIntl(); + const user = maybe(() => order.user); const [userDisplayName, setUserDisplayName] = useStateFromProps( @@ -88,7 +91,10 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( return ( - {i18n.t("Edit")} + {intl.formatMessage(buttonMessages.edit)} ) } @@ -133,7 +139,9 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( displayValue={userDisplayName} fetchChoices={fetchUsers} loading={loading} - placeholder={i18n.t("Search Customers")} + placeholder={intl.formatMessage({ + defaultMessage: "Search Customers" + })} onChange={handleUserChange} name="query" value={data.query} @@ -142,7 +150,9 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( }} ) : user === null ? ( - {i18n.t("Anonymous user")} + + + ) : ( <> @@ -154,14 +164,21 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( href={createHref(customerUrl(user.id))} onClick={onProfileView} > - {i18n.t("View Profile")} +
{/* TODO: Uncomment it after adding ability to filter orders by customer */} {/*
- {i18n.t("View Orders")} -
*/} + + + +
*/} )} @@ -169,14 +186,23 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })(
- {i18n.t("Contact information")} +
{maybe(() => order.userEmail) === undefined ? ( ) : order.userEmail === null ? ( - {i18n.t("Not set")} + + + ) : ( order.userEmail)}`} @@ -190,7 +216,7 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })(
- {i18n.t("Shipping Address")} + {canEditAddresses && (
@@ -200,7 +226,7 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( onClick={onShippingAddressEdit} disabled={!onShippingAddressEdit && user === undefined} > - {i18n.t("Edit")} +
)} @@ -208,7 +234,13 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( {shippingAddress === undefined ? ( ) : shippingAddress === null ? ( - {i18n.t("Not set")} + + + ) : ( <> {shippingAddress.companyName && ( @@ -243,7 +275,7 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })(
- {i18n.t("Billing Address")} + {canEditAddresses && (
@@ -253,7 +285,7 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( onClick={onBillingAddressEdit} disabled={!onBillingAddressEdit && user === undefined} > - {i18n.t("Edit")} +
)} @@ -261,9 +293,20 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( {billingAddress === undefined ? ( ) : billingAddress === null ? ( - {i18n.t("Not set")} + + + ) : maybe(() => shippingAddress.id) === billingAddress.id ? ( - {i18n.t("Same as shipping address")} + + + ) : ( <> {billingAddress.companyName && ( diff --git a/src/orders/components/OrderCustomerEditDialog/OrderCustomerEditDialog.tsx b/src/orders/components/OrderCustomerEditDialog/OrderCustomerEditDialog.tsx index 7000c2289..a629fc285 100644 --- a/src/orders/components/OrderCustomerEditDialog/OrderCustomerEditDialog.tsx +++ b/src/orders/components/OrderCustomerEditDialog/OrderCustomerEditDialog.tsx @@ -10,12 +10,13 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { SingleAutocompleteSelectField } from "@saleor/components/SingleAutocompleteSelectField"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; const styles = (theme: Theme) => createStyles({ @@ -76,7 +77,12 @@ const OrderCustomerEditDialog = withStyles(styles, { : []; return ( - {i18n.t("Edit customer details")} + + + - {i18n.t("Confirm", { context: "button" })} + diff --git a/src/orders/components/OrderCustomerNote/OrderCustomerNote.tsx b/src/orders/components/OrderCustomerNote/OrderCustomerNote.tsx index 4a3b075ff..affb2e180 100644 --- a/src/orders/components/OrderCustomerNote/OrderCustomerNote.tsx +++ b/src/orders/components/OrderCustomerNote/OrderCustomerNote.tsx @@ -2,10 +2,10 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; interface OrderCustomerNoteProps { note: string; @@ -13,24 +13,29 @@ interface OrderCustomerNoteProps { export const OrderCustomerNote: React.StatelessComponent< OrderCustomerNoteProps -> = ({ note }) => ( - - - - {note === undefined ? ( - - ) : note === "" ? ( - - {i18n.t("No notes from customer")} - - ) : ( - {note} - )} - - -); +> = ({ note }) => { + const intl = useIntl(); + + return ( + + + + {note === undefined ? ( + + ) : note === "" ? ( + + + + ) : ( + {note} + )} + + + ); +}; export default OrderCustomerNote; diff --git a/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx b/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx index b20a70e10..8e2b332bd 100644 --- a/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx +++ b/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx @@ -6,6 +6,7 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardMenu from "@saleor/components/CardMenu"; @@ -15,7 +16,7 @@ import { DateTime } from "@saleor/components/Date"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe, renderCollection } from "../../../misc"; import { OrderStatus } from "../../../types/globalTypes"; import { OrderDetails_order } from "../../types/OrderDetails"; @@ -81,6 +82,8 @@ const OrderDetailsPage = withStyles(styles, { name: "OrderDetailsPage" })( onShippingAddressEdit, onProfileView }: OrderDetailsPageProps) => { + const intl = useIntl(); + const canCancel = maybe(() => order.status) !== OrderStatus.CANCELED; const canEditAddresses = maybe(() => order.status) !== OrderStatus.CANCELED; const canFulfill = maybe(() => order.status) !== OrderStatus.CANCELED; @@ -90,7 +93,9 @@ const OrderDetailsPage = withStyles(styles, { name: "OrderDetailsPage" })( return ( - {i18n.t("Orders")} + + {intl.formatMessage(sectionNames.orders)} + order.number) ? "#" + order.number : undefined} @@ -99,7 +104,10 @@ const OrderDetailsPage = withStyles(styles, { name: "OrderDetailsPage" })( = ({ confirmButtonState, onClose, onConfirm, open, orderNumber }) => ( - - #{{ number }}?", - { - context: "modal", - number: orderNumber - } - ) - }} - /> - -); +> = ({ confirmButtonState, onClose, onConfirm, open, orderNumber }) => { + const intl = useIntl(); + + return ( + + + + + + ); +}; OrderDraftCancelDialog.displayName = "OrderDraftCancelDialog"; export default OrderDraftCancelDialog; diff --git a/src/orders/components/OrderDraftDetails/OrderDraftDetails.tsx b/src/orders/components/OrderDraftDetails/OrderDraftDetails.tsx index 3eeb932e7..73ad251f5 100644 --- a/src/orders/components/OrderDraftDetails/OrderDraftDetails.tsx +++ b/src/orders/components/OrderDraftDetails/OrderDraftDetails.tsx @@ -2,9 +2,9 @@ import Button from "@material-ui/core/Button"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { OrderDetails_order } from "../../types/OrderDetails"; import OrderDraftDetailsProducts, { @@ -29,34 +29,40 @@ const OrderDraftDetails: React.StatelessComponent = ({ onOrderLineChange, onOrderLineRemove, onShippingMethodEdit -}) => ( - - - {i18n.t("Add products", { - context: "button" - })} - - } - /> - order.lines)} - onOrderLineChange={onOrderLineChange} - onOrderLineRemove={onOrderLineRemove} - /> - {maybe(() => order.lines.length) !== 0 && ( - - - - )} - -); +}) => { + const intl = useIntl(); + + return ( + + + + + } + /> + order.lines)} + onOrderLineChange={onOrderLineChange} + onOrderLineRemove={onOrderLineRemove} + /> + {maybe(() => order.lines.length) !== 0 && ( + + + + )} + + ); +}; OrderDraftDetails.displayName = "OrderDraftDetails"; export default OrderDraftDetails; diff --git a/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.tsx b/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.tsx index 2d8d922e3..099469372 100644 --- a/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.tsx +++ b/src/orders/components/OrderDraftDetailsProducts/OrderDraftDetailsProducts.tsx @@ -14,6 +14,7 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage } from "react-intl"; import { DebounceForm } from "@saleor/components/DebounceForm"; import Form from "@saleor/components/Form"; @@ -22,7 +23,6 @@ import Skeleton from "@saleor/components/Skeleton"; import TableCellAvatar, { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { OrderDetails_order_lines } from "../../types/OrderDetails"; @@ -89,17 +89,26 @@ const OrderDraftDetailsProducts = withStyles(styles, { - {i18n.t("Product", { context: "table header" })} + - {i18n.t("Quantity", { context: "table header" })} + - {i18n.t("Price", { context: "table header" })} + - {i18n.t("Total", { context: "table header" })} + @@ -109,7 +118,7 @@ const OrderDraftDetailsProducts = withStyles(styles, { {maybe(() => lines.length) === 0 ? ( - {i18n.t("No Products added to Order")} + ) : ( diff --git a/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.tsx b/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.tsx index 1ca1898c6..531799ba7 100644 --- a/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.tsx +++ b/src/orders/components/OrderDraftDetailsSummary/OrderDraftDetailsSummary.tsx @@ -5,11 +5,11 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; import Link from "@saleor/components/Link"; import Money from "@saleor/components/Money"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { OrderDetails_order } from "../../types/OrderDetails"; @@ -39,7 +39,12 @@ const OrderDraftDetailsSummary = withStyles(styles, { {maybe(() => order.subtotal) ? ( <> - {i18n.t("Subtotal")} + + + @@ -59,11 +64,16 @@ const OrderDraftDetailsSummary = withStyles(styles, { order.availableShippingMethods.length > 0 ? ( - {i18n.t("Add shipping carrier")} + ) : ( - {i18n.t("No applicable shipping carriers")} + + + ) ) : ( <> @@ -90,7 +100,9 @@ const OrderDraftDetailsSummary = withStyles(styles, { {maybe(() => order.total.tax) !== undefined ? ( <> - {i18n.t("Taxes (VAT included)")} + + + @@ -104,7 +116,12 @@ const OrderDraftDetailsSummary = withStyles(styles, { {maybe(() => order.total.gross) !== undefined ? ( <> - {i18n.t("Total")} + + + diff --git a/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.tsx b/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.tsx index f8b72cb60..a6138c3aa 100644 --- a/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.tsx +++ b/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.tsx @@ -1,9 +1,9 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, IntlShape, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import i18n from "../../../i18n"; export type OrderDraftFinalizeWarning = | "no-shipping" @@ -21,18 +21,28 @@ export interface OrderDraftFinalizeDialogProps { onConfirm: () => void; } -const warningToText = (warning: OrderDraftFinalizeWarning) => { +const warningToText = (warning: OrderDraftFinalizeWarning, intl: IntlShape) => { switch (warning) { case "no-shipping": - return i18n.t("No shipping address"); + return intl.formatMessage({ + defaultMessage: "No shipping address" + }); case "no-billing": - return i18n.t("No billing address"); + return intl.formatMessage({ + defaultMessage: "No billing address" + }); case "no-user": - return i18n.t("No user information"); + return intl.formatMessage({ + defaultMessage: "No user information" + }); case "no-shipping-method": - return i18n.t("Some products require shipping, but no method provided"); + return intl.formatMessage({ + defaultMessage: "Some products require shipping, but no method provided" + }); case "unnecessary-shipping-method": - return i18n.t("Shipping method provided, but no product requires it"); + return intl.formatMessage({ + defaultMessage: "Shipping method provided, but no product requires it" + }); } }; @@ -45,48 +55,54 @@ const OrderDraftFinalizeDialog: React.StatelessComponent< onClose, onConfirm, orderNumber -}) => ( - 0 ? i18n.t("Finalize anyway") : i18n.t("Finalize") - } - confirmButtonState={confirmButtonState} - variant={warnings.length > 0 ? "delete" : "default"} - > - - {warnings.length > 0 && ( - <> -

- {i18n.t( - "There are missing or incorrect informations about this order:" - )} -

-
    - {warnings.map(warning => ( -
  • {warningToText(warning)}
  • - ))} -
- - )} - #{{ number }}?", - { - context: "modal", - number: orderNumber - } - ) - }} - /> -
-
-); +}) => { + const intl = useIntl(); + + return ( + 0 + ? intl.formatMessage({ + defaultMessage: "Finalize anyway", + description: "button" + }) + : intl.formatMessage({ + defaultMessage: "Finalize", + description: "button" + }) + } + confirmButtonState={confirmButtonState} + variant={warnings.length > 0 ? "delete" : "default"} + > + + {warnings.length > 0 && ( + <> +

+ +

+
    + {warnings.map(warning => ( +
  • {warningToText(warning, intl)}
  • + ))} +
+ + )} + +
+
+ ); +}; OrderDraftFinalizeDialog.displayName = "OrderDraftFinalize"; export default OrderDraftFinalizeDialog; diff --git a/src/orders/components/OrderDraftList/OrderDraftList.tsx b/src/orders/components/OrderDraftList/OrderDraftList.tsx index 8ebfde633..70946e36d 100644 --- a/src/orders/components/OrderDraftList/OrderDraftList.tsx +++ b/src/orders/components/OrderDraftList/OrderDraftList.tsx @@ -10,6 +10,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import { DateTime } from "@saleor/components/Date"; @@ -17,7 +18,6 @@ import Money from "@saleor/components/Money"; import Skeleton from "@saleor/components/Skeleton"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection, @@ -78,13 +78,16 @@ export const OrderDraftList = withStyles(styles, { name: "OrderDraftList" })( toggleAll, toolbar }: OrderDraftListProps) => { + const intl = useIntl(); + const orderDraftList = orders ? orders.map(order => ({ ...order, - paymentStatus: transformPaymentStatus(order.paymentStatus), - status: transformOrderStatus(order.status) + paymentStatus: transformPaymentStatus(order.paymentStatus, intl), + status: transformOrderStatus(order.status, intl) })) : undefined; + return ( - {i18n.t("No. of Order", { context: "table header" })} + - {i18n.t("Date", { context: "table header" })} + - {i18n.t("Customer", { context: "table header" })} + - {i18n.t("Total", { context: "table header" })} + @@ -185,7 +194,7 @@ export const OrderDraftList = withStyles(styles, { name: "OrderDraftList" })( () => ( - {i18n.t("No orders found")} + ) diff --git a/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx b/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx index a172986a6..23fcff5d1 100644 --- a/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx +++ b/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx @@ -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 Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { OrderDraftList_draftOrders_edges_node } from "../../types/OrderDraftList"; import OrderDraftList from "../OrderDraftList"; @@ -18,22 +19,30 @@ const OrderDraftListPage: React.StatelessComponent = ({ disabled, onAdd, ...listProps -}) => ( - - - - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + + + ); +}; OrderDraftListPage.displayName = "OrderDraftListPage"; export default OrderDraftListPage; diff --git a/src/orders/components/OrderDraftPage/OrderDraftPage.tsx b/src/orders/components/OrderDraftPage/OrderDraftPage.tsx index 7e357f547..4afab620c 100644 --- a/src/orders/components/OrderDraftPage/OrderDraftPage.tsx +++ b/src/orders/components/OrderDraftPage/OrderDraftPage.tsx @@ -6,6 +6,7 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardMenu from "@saleor/components/CardMenu"; @@ -16,8 +17,8 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import Skeleton from "@saleor/components/Skeleton"; +import { sectionNames } from "@saleor/intl"; import { SearchCustomers_customers_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { DraftOrderInput } from "../../../types/globalTypes"; import { OrderDetails_order } from "../../types/OrderDetails"; @@ -87,69 +88,83 @@ const OrderDraftPage = withStyles(styles, { name: "OrderDraftPage" })( order, users, usersLoading - }: OrderDraftPageProps) => ( - - {i18n.t("Orders")} - order.number) ? "#" + order.number : undefined} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.draftOrders)} + + order.number) ? "#" + order.number : undefined} + > + + +
+ {order && order.created ? ( + + + + ) : ( + + )} +
+ +
+ + order.events)} + onNoteAdd={onNoteAdd} + /> +
+
+ +
+
+ order.canFinalize)} + onCancel={onBack} + onSave={onDraftFinalize} + labels={{ + save: intl.formatMessage({ + defaultMessage: "Finalize", + description: "button" + }) + }} /> -
-
- {order && order.created ? ( - - - - ) : ( - - )} -
- -
- - order.events)} - onNoteAdd={onNoteAdd} - /> -
-
- -
-
- order.canFinalize)} - onCancel={onBack} - onSave={onDraftFinalize} - labels={{ save: i18n.t("Finalize", { context: "button" }) }} - /> -
- ) + + ); + } ); OrderDraftPage.displayName = "OrderDraftPage"; export default OrderDraftPage; diff --git a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx index 041c4acb3..8c35c4a49 100644 --- a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx +++ b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx @@ -14,6 +14,7 @@ import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardMenu from "@saleor/components/CardMenu"; import CardTitle from "@saleor/components/CardTitle"; @@ -23,7 +24,6 @@ import StatusLabel from "@saleor/components/StatusLabel"; import TableCellAvatar, { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { FulfillmentStatus } from "../../../types/globalTypes"; import { OrderDetails_order_fulfillments } from "../../types/OrderDetails"; @@ -81,8 +81,14 @@ const OrderFulfillment = withStyles(styles, { name: "OrderFulfillment" })( onOrderFulfillmentCancel, onTrackingCodeAdd }: OrderFulfillmentProps) => { + const intl = useIntl(); + const lines = maybe(() => fulfillment.lines); const status = maybe(() => fulfillment.status); + const quantity = lines + ? lines.map(line => line.quantity).reduce((prev, curr) => prev + curr, 0) + : "..."; + return ( {status === FulfillmentStatus.FULFILLED - ? i18n.t("Fulfilled ({{ quantity }})", { - quantity: lines - .map(line => line.quantity) - .reduce((prev, curr) => prev + curr, 0) - }) - : i18n.t("Cancelled ({{ quantity }})", { - quantity: lines - .map(line => line.quantity) - .reduce((prev, curr) => prev + curr, 0) - })} + ? intl.formatMessage( + { + defaultMessage: "Fulfilled ({quantity})", + description: "section header" + }, + { + quantity + } + ) + : intl.formatMessage( + { + defaultMessage: "Fulfilled ({quantity})", + description: "section header" + }, + { + quantity + } + )} {maybe( () => `#${orderNumber}-${fulfillment.fulfillmentOrder}` @@ -122,8 +136,9 @@ const OrderFulfillment = withStyles(styles, { name: "OrderFulfillment" })( - {i18n.t("Product")} + - {i18n.t("Quantity")} + - {i18n.t("Price")} + - {i18n.t("Total")} + @@ -194,9 +221,12 @@ const OrderFulfillment = withStyles(styles, { name: "OrderFulfillment" })( {maybe(() => fulfillment.trackingNumber) && ( - {i18n.t("Tracking Number: {{ trackingNumber }}", { - trackingNumber: fulfillment.trackingNumber - })} + )} @@ -205,7 +235,10 @@ const OrderFulfillment = withStyles(styles, { name: "OrderFulfillment" })( {status === FulfillmentStatus.FULFILLED && !fulfillment.trackingNumber && ( )} diff --git a/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx b/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx index 8db361464..2517c6623 100644 --- a/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx +++ b/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx @@ -11,13 +11,14 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox"; import Form from "@saleor/components/Form"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; export interface FormData { restock: boolean; @@ -50,43 +51,56 @@ const OrderFulfillmentCancelDialog = withStyles(styles, { open, onConfirm, onClose - }: OrderFulfillmentCancelDialogProps) => ( - -
- {({ change, data, submit }) => ( - <> - - {i18n.t("Cancel fulfillment", { context: "title" })} - - - - {i18n.t("Are you sure you want to cancel this fulfillment?")} - - - - - - - {i18n.t("Cancel fulfillment", { context: "button" })} - - - - )} - -
- ) + }: OrderFulfillmentCancelDialogProps) => { + const intl = useIntl(); + + return ( + +
+ {({ change, data, submit }) => ( + <> + + + + + + + + + + + + + + + + + )} + +
+ ); + } ); OrderFulfillmentCancelDialog.displayName = "OrderFulfillmentCancelDialog"; export default OrderFulfillmentCancelDialog; diff --git a/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.tsx b/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.tsx index 8be5156cc..6c7bfcee6 100644 --- a/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.tsx +++ b/src/orders/components/OrderFulfillmentDialog/OrderFulfillmentDialog.tsx @@ -16,6 +16,7 @@ import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState @@ -25,7 +26,7 @@ import { FormSpacer } from "@saleor/components/FormSpacer"; import TableCellAvatar, { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe } from "../../../misc"; import { OrderDetails_order_lines } from "../../types/OrderDetails"; @@ -83,125 +84,143 @@ const OrderFulfillmentDialog = withStyles(styles, { lines, onClose, onSubmit - }: OrderFulfillmentDialogProps) => ( - -
- lines.map( - product => product.quantity - product.quantityFulfilled - ), - [] - ), - trackingNumber: "" - }} - onSubmit={onSubmit} - > - {({ data, change }) => { - const handleQuantityChange = ( - productIndex: number, - event: React.ChangeEvent - ) => { - const newData = data.lines; - newData[productIndex] = event.target.value; - change({ - target: { - name: "lines", - value: newData - } - } as any); - }; - return ( - <> - {i18n.t("Fulfill products")} -
- - - - - {i18n.t("Product name")} - - - - {i18n.t("SKU")} - - - {i18n.t("Quantity")} - - - - - {lines.map((product, productIndex) => { - const remainingQuantity = - product.quantity - product.quantityFulfilled; - return ( - - product.thumbnail.url)} - > - {product.productName} - - - {product.productSku} - - -
- - handleQuantityChange(productIndex, event) - } - error={ - remainingQuantity < data.lines[productIndex] - } - /> -
- / {remainingQuantity} + }: OrderFulfillmentDialogProps) => { + const intl = useIntl(); + + return ( + + + lines.map( + product => product.quantity - product.quantityFulfilled + ), + [] + ), + trackingNumber: "" + }} + onSubmit={onSubmit} + > + {({ data, change }) => { + const handleQuantityChange = ( + productIndex: number, + event: React.ChangeEvent + ) => { + const newData = data.lines; + newData[productIndex] = event.target.value; + change({ + target: { + name: "lines", + value: newData + } + } as any); + }; + return ( + <> + + + +
+ + + + + + + + + + + + + + + + + {lines.map((product, productIndex) => { + const remainingQuantity = + product.quantity - product.quantityFulfilled; + return ( + + product.thumbnail.url)} + > + {product.productName} + + + {product.productSku} + + +
+ + handleQuantityChange(productIndex, event) + } + error={ + remainingQuantity < data.lines[productIndex] + } + /> +
+ / {remainingQuantity} +
- -
-
- ); - })} -
-
- - - - - - - - {i18n.t("Confirm", { context: "button" })} - - - - ); - }} - - - ) + + + ); + })} + + + + + + + + + + + + + + ); + }} + + + ); + } ); OrderFulfillmentDialog.displayName = "OrderFulfillmentDialog"; export default OrderFulfillmentDialog; diff --git a/src/orders/components/OrderFulfillmentTrackingDialog/OrderFulfillmentTrackingDialog.tsx b/src/orders/components/OrderFulfillmentTrackingDialog/OrderFulfillmentTrackingDialog.tsx index df3df08fe..4de13a599 100644 --- a/src/orders/components/OrderFulfillmentTrackingDialog/OrderFulfillmentTrackingDialog.tsx +++ b/src/orders/components/OrderFulfillmentTrackingDialog/OrderFulfillmentTrackingDialog.tsx @@ -5,12 +5,13 @@ 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 i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; export interface FormData { trackingNumber: string; @@ -26,40 +27,49 @@ interface OrderFulfillmentTrackingDialogProps { const OrderFulfillmentTrackingDialog: React.StatelessComponent< OrderFulfillmentTrackingDialogProps -> = ({ confirmButtonState, open, trackingNumber, onConfirm, onClose }) => ( - -
- {({ change, data, submit }) => ( - <> - - {i18n.t("Add tracking code", { context: "title" })} - - - - - - - - {i18n.t("Confirm", { context: "button" })} - - - - )} -
-
-); +> = ({ confirmButtonState, open, trackingNumber, onConfirm, onClose }) => { + const intl = useIntl(); + + return ( + +
+ {({ change, data, submit }) => ( + <> + + + + + + + + + + + + + + )} +
+
+ ); +}; OrderFulfillmentTrackingDialog.displayName = "OrderFulfillmentTrackingDialog"; export default OrderFulfillmentTrackingDialog; diff --git a/src/orders/components/OrderHistory/OrderHistory.tsx b/src/orders/components/OrderHistory/OrderHistory.tsx index e04b7e204..606f83a77 100644 --- a/src/orders/components/OrderHistory/OrderHistory.tsx +++ b/src/orders/components/OrderHistory/OrderHistory.tsx @@ -6,6 +6,7 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, IntlShape, useIntl } from "react-intl"; import Form from "@saleor/components/Form"; import Hr from "@saleor/components/Hr"; @@ -16,7 +17,6 @@ import { TimelineEvent, TimelineNote } from "@saleor/components/Timeline"; -import i18n from "../../../i18n"; import { OrderEventsEmailsEnum, OrderEventsEnum @@ -27,115 +27,152 @@ export interface FormData { message: string; } -const getEventMessage = (event: OrderDetails_order_events) => { +const getEventMessage = (event: OrderDetails_order_events, intl: IntlShape) => { switch (event.type) { case OrderEventsEnum.CANCELED: - return i18n.t("Order was cancelled", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Order was cancelled", + description: "order history message" }); case OrderEventsEnum.DRAFT_ADDED_PRODUCTS: - return i18n.t("Products were added to draft order", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Products were added to draft order", + description: "order history message" }); case OrderEventsEnum.DRAFT_CREATED: - return i18n.t("Draft order was created", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Draft order was created", + description: "order history message" }); case OrderEventsEnum.DRAFT_REMOVED_PRODUCTS: - return i18n.t("Products were removed from draft order", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Products were removed from draft order", + description: "order history message" }); case OrderEventsEnum.EMAIL_SENT: switch (event.emailType) { case OrderEventsEmailsEnum.DIGITAL_LINKS: - return i18n.t("Links to the order's digital goods were sent", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Links to the order's digital goods were sent", + description: "order history message" }); case OrderEventsEmailsEnum.FULFILLMENT_CONFIRMATION: - return i18n.t("Fulfillment confirmation was sent to customer", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Fulfillment confirmation was sent to customer", + description: "order history message" }); case OrderEventsEmailsEnum.ORDER_CONFIRMATION: - return i18n.t("Order confirmation was sent to customer", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Order confirmation was sent to customer", + description: "order history message" }); case OrderEventsEmailsEnum.PAYMENT_CONFIRMATION: - return i18n.t("Payment confirmation was sent to customer", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Payment confirmation was sent to customer", + description: "order history message" }); case OrderEventsEmailsEnum.SHIPPING_CONFIRMATION: - return i18n.t("Shipping details was sent to customer", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Shipping details was sent to customer", + description: "order history message" }); case OrderEventsEmailsEnum.TRACKING_UPDATED: - return i18n.t("Shipping tracking number was sent to customer", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Shipping tracking number was sent to customer", + description: "order history message" }); } case OrderEventsEnum.FULFILLMENT_CANCELED: - return i18n.t("Fulfillment was cancelled", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Fulfillment was cancelled", + description: "order history message" }); case OrderEventsEnum.FULFILLMENT_FULFILLED_ITEMS: - return i18n.t("Fulfilled {{ quantity }} items", { - context: "order history message", - quantity: event.quantity - }); + return intl.formatMessage( + { + defaultMessage: "Fulfilled {quantity} items", + description: "order history message" + }, + { + quantity: event.quantity + } + ); case OrderEventsEnum.FULFILLMENT_RESTOCKED_ITEMS: - return i18n.t("Restocked {{ quantity }} items", { - context: "order history message", - quantity: event.quantity - }); + return intl.formatMessage( + { + defaultMessage: "Restocked {quantity} items", + description: "order history message" + }, + { + quantity: event.quantity + } + ); case OrderEventsEnum.NOTE_ADDED: - return i18n.t("Note was added to the order", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Note was added to the order", + description: "order history message" }); case OrderEventsEnum.ORDER_FULLY_PAID: - return i18n.t("Order was fully paid", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Order was fully paid", + description: "order history message" }); case OrderEventsEnum.ORDER_MARKED_AS_PAID: - return i18n.t("Marked order as paid", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Marked order as paid", + description: "order history message" }); case OrderEventsEnum.OTHER: return event.message; case OrderEventsEnum.OVERSOLD_ITEMS: - return i18n.t("Oversold {{ quantity }} items", { - context: "order history message", - quantity: event.quantity - }); + return intl.formatMessage( + { + defaultMessage: "Oversold {quantity} items", + description: "order history message" + }, + { + quantity: event.quantity + } + ); case OrderEventsEnum.PAYMENT_CAPTURED: - return i18n.t("Payment was captured", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Payment was captured", + description: "order history message" }); case OrderEventsEnum.PAYMENT_FAILED: - return i18n.t("Payment failed", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Payment failed", + description: "order history message" }); case OrderEventsEnum.PAYMENT_REFUNDED: - return i18n.t("Payment was refunded", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Payment was refunded", + description: "order history message" }); case OrderEventsEnum.PAYMENT_VOIDED: - return i18n.t("Payment was voided", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Payment was voided", + description: "order history message" }); case OrderEventsEnum.PLACED: - return i18n.t("Order was placed", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Order was placed", + description: "order history message" }); case OrderEventsEnum.PLACED_FROM_DRAFT: - return i18n.t("Order was created from draft", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Order was created from draft", + description: "order history message" }); case OrderEventsEnum.TRACKING_UPDATED: - return i18n.t("Updated fulfillment group's tracking number", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Updated fulfillment group's tracking number", + description: "order history message" }); case OrderEventsEnum.UPDATED_ADDRESS: - return i18n.t("Order address was updated", { - context: "order history message" + return intl.formatMessage({ + defaultMessage: "Order address was updated", + description: "order history message" }); } }; @@ -158,51 +195,55 @@ interface OrderHistoryProps extends WithStyles { } const OrderHistory = withStyles(styles, { name: "OrderHistory" })( - ({ classes, history, onNoteAdd }: OrderHistoryProps) => ( -
- - {i18n.t("Order History")} - -
- {history ? ( - -
- {({ change, data, submit }) => ( - - )} - - {history - .slice() - .reverse() - .map(event => { - if (event.type === OrderEventsEnum.NOTE_ADDED) { + ({ classes, history, onNoteAdd }: OrderHistoryProps) => { + const intl = useIntl(); + + return ( +
+ + + +
+ {history ? ( + +
+ {({ change, data, submit }) => ( + + )} + + {history + .slice() + .reverse() + .map(event => { + if (event.type === OrderEventsEnum.NOTE_ADDED) { + return ( + + ); + } return ( - ); - } - return ( - - ); - })} -
- ) : ( - - )} -
- ) + })} +
+ ) : ( + + )} +
+ ); + } ); OrderHistory.displayName = "OrderHistory"; export default OrderHistory; diff --git a/src/orders/components/OrderList/OrderList.tsx b/src/orders/components/OrderList/OrderList.tsx index c0b772ab7..fac1f596d 100644 --- a/src/orders/components/OrderList/OrderList.tsx +++ b/src/orders/components/OrderList/OrderList.tsx @@ -10,6 +10,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import { DateTime } from "@saleor/components/Date"; @@ -18,7 +19,6 @@ import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection, @@ -85,11 +85,13 @@ export const OrderList = withStyles(styles, { name: "OrderList" })( toggleAll, toolbar }: OrderListProps) => { + const intl = useIntl(); + const orderList = orders ? orders.map(order => ({ ...order, - paymentStatus: transformPaymentStatus(order.paymentStatus), - status: transformOrderStatus(order.status) + paymentStatus: transformPaymentStatus(order.paymentStatus, intl), + status: transformOrderStatus(order.status, intl) })) : undefined; return ( @@ -103,22 +105,34 @@ export const OrderList = withStyles(styles, { name: "OrderList" })( toolbar={toolbar} > - {i18n.t("No. of Order", { context: "table header" })} + - {i18n.t("Date", { context: "table header" })} + - {i18n.t("Customer", { context: "table header" })} + - {i18n.t("Payment", { context: "table header" })} + - {i18n.t("Fulfillment status", { context: "table header" })} + - {i18n.t("Total", { context: "table header" })} + @@ -220,7 +234,7 @@ export const OrderList = withStyles(styles, { name: "OrderList" })( () => ( - {i18n.t("No orders found")} + ) diff --git a/src/orders/components/OrderListFilter/OrderListFilter.tsx b/src/orders/components/OrderListFilter/OrderListFilter.tsx index a76489479..676a3548c 100644 --- a/src/orders/components/OrderListFilter/OrderListFilter.tsx +++ b/src/orders/components/OrderListFilter/OrderListFilter.tsx @@ -1,11 +1,11 @@ import moment from "moment-timezone"; import React from "react"; +import { useIntl } from "react-intl"; import { DateContext } from "@saleor/components/Date/DateContext"; import { FieldType, IFilter } from "@saleor/components/Filter"; import FilterBar from "@saleor/components/FilterBar"; import TimezoneContext from "@saleor/components/Timezone"; -import i18n from "../../../i18n"; import { FilterProps } from "../../../types"; import { OrderStatusFilter } from "../../../types/globalTypes"; import { OrderListUrlFilters } from "../../urls"; @@ -26,6 +26,7 @@ export enum OrderFilterKeys { const OrderListFilter: React.FC = props => { const date = React.useContext(DateContext); const tz = React.useContext(TimezoneContext); + const intl = useIntl(); const filterMenu: IFilter = [ { @@ -40,7 +41,9 @@ const OrderListFilter: React.FC = props => { .toISOString() .split("T")[0] // Remove timezone }, - label: i18n.t("Last 7 Days"), + label: intl.formatMessage({ + defaultMessage: "Last 7 Days" + }), value: OrderFilterKeys.dateLastWeek.toString() }, { @@ -53,7 +56,9 @@ const OrderListFilter: React.FC = props => { .toISOString() .split("T")[0] // Remove timezone }, - label: i18n.t("Last 30 Days"), + label: intl.formatMessage({ + defaultMessage: "Last 30 Days" + }), value: OrderFilterKeys.dateLastMonth.toString() }, { @@ -66,58 +71,90 @@ const OrderListFilter: React.FC = props => { .toISOString() .split("T")[0] // Remove timezone }, - label: i18n.t("Last Year"), + label: intl.formatMessage({ + defaultMessage: "Last Year" + }), value: OrderFilterKeys.dateLastYear.toString() }, { children: [], data: { - additionalText: i18n.t("equals"), + additionalText: intl.formatMessage({ + defaultMessage: "equals" + }), fieldLabel: null, type: FieldType.date }, - label: i18n.t("Specific Date"), + label: intl.formatMessage({ + defaultMessage: "Specific Date" + }), value: OrderFilterKeys.dateEqual.toString() }, { children: [], data: { - fieldLabel: i18n.t("Range"), + fieldLabel: intl.formatMessage({ + defaultMessage: "Range" + }), type: FieldType.rangeDate }, - label: i18n.t("Range"), + label: intl.formatMessage({ + defaultMessage: "Range" + }), value: OrderFilterKeys.dateRange.toString() } ], data: { - fieldLabel: i18n.t("Date"), + fieldLabel: intl.formatMessage({ + defaultMessage: "Date" + }), type: FieldType.select }, - label: i18n.t("Date"), + label: intl.formatMessage({ + defaultMessage: "Date" + }), value: OrderFilterKeys.date.toString() }, { children: [], data: { - additionalText: i18n.t("is set as"), - fieldLabel: i18n.t("Status"), + additionalText: intl.formatMessage({ + defaultMessage: "is set as", + description: "date is set as" + }), + fieldLabel: intl.formatMessage({ + defaultMessage: "Status", + description: "order fulfillment status" + }), options: [ { - label: i18n.t("Fulfilled"), + label: intl.formatMessage({ + defaultMessage: "Fulfilled", + description: "order fulfillment status" + }), value: OrderStatusFilter.FULFILLED.toString() }, { - label: i18n.t("Partially Fulfilled"), + label: intl.formatMessage({ + defaultMessage: "Partially Fulfilled", + description: "order fulfillment status" + }), value: OrderStatusFilter.PARTIALLY_FULFILLED.toString() }, { - label: i18n.t("Unfulfilled"), + label: intl.formatMessage({ + defaultMessage: "Unfulfilled", + description: "order fulfillment status" + }), value: OrderStatusFilter.UNFULFILLED.toString() } ], type: FieldType.select }, - label: i18n.t("Fulfillment Status"), + label: intl.formatMessage({ + defaultMessage: "Fulfillment Status", + description: "order" + }), value: OrderFilterKeys.fulfillment.toString() } ]; diff --git a/src/orders/components/OrderListPage/OrderListPage.tsx b/src/orders/components/OrderListPage/OrderListPage.tsx index 96d25ba14..3ccd68653 100644 --- a/src/orders/components/OrderListPage/OrderListPage.tsx +++ b/src/orders/components/OrderListPage/OrderListPage.tsx @@ -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 Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { FilterPageProps, ListActions, PageListProps } from "@saleor/types"; import { OrderList_orders_edges_node } from "../../types/OrderList"; import { OrderListUrlFilters } from "../../urls"; @@ -33,33 +34,48 @@ const OrderListPage: React.FC = ({ onTabChange, onFilterDelete, ...listProps -}) => ( - - - - - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + + + + + + ); +}; OrderListPage.displayName = "OrderListPage"; export default OrderListPage; diff --git a/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.tsx b/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.tsx index 19e83e459..f0dad31dd 100644 --- a/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.tsx +++ b/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.tsx @@ -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 "../../../i18n"; export interface OrderMarkAsPaidDialogProps { confirmButtonState: ConfirmButtonTransitionState; @@ -14,20 +14,25 @@ export interface OrderMarkAsPaidDialogProps { const OrderMarkAsPaidDialog: React.StatelessComponent< OrderMarkAsPaidDialogProps -> = ({ confirmButtonState, onClose, onConfirm, open }) => ( - - - {i18n.t("Are you sure you want to mark this order as paid?", { - context: "modal content" +> = ({ confirmButtonState, onClose, onConfirm, open }) => { + const intl = useIntl(); + + return ( + - -); + onClose={onClose} + onConfirm={onConfirm} + > + + + + + ); +}; OrderMarkAsPaidDialog.displayName = "OrderMarkAsPaidDialog"; export default OrderMarkAsPaidDialog; diff --git a/src/orders/components/OrderPayment/OrderPayment.tsx b/src/orders/components/OrderPayment/OrderPayment.tsx index 2701e0c81..80fc40273 100644 --- a/src/orders/components/OrderPayment/OrderPayment.tsx +++ b/src/orders/components/OrderPayment/OrderPayment.tsx @@ -9,13 +9,13 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { Hr } from "@saleor/components/Hr"; import Money, { subtractMoney } from "@saleor/components/Money"; import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; -import i18n from "../../../i18n"; import { maybe, transformPaymentStatus } from "../../../misc"; import { OrderAction, OrderStatus } from "../../../types/globalTypes"; import { OrderDetails_order } from "../../types/OrderDetails"; @@ -52,6 +52,8 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( onRefund, onVoid }: OrderPaymentProps) => { + const intl = useIntl(); + const canCapture = maybe(() => order.actions, []).includes( OrderAction.CAPTURE ); @@ -62,7 +64,10 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( const canMarkAsPaid = maybe(() => order.actions, []).includes( OrderAction.MARK_AS_PAID ); - const payment = transformPaymentStatus(maybe(() => order.paymentStatus)); + const payment = transformPaymentStatus( + maybe(() => order.paymentStatus), + intl + ); return ( - {i18n.t("Subtotal")} + + + {maybe(() => order.lines) === undefined ? ( ) : ( - i18n.t("{{ quantity }} items", { - quantity: order.lines - .map(line => line.quantity) - .reduce((curr, prev) => prev + curr, 0) - }) + line.quantity) + .reduce((curr, prev) => prev + curr, 0) + }} + /> )} @@ -99,14 +113,23 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( - {i18n.t("Taxes")} + + + {maybe(() => order.total.tax) === undefined ? ( ) : order.total.tax.amount > 0 ? ( - i18n.t("VAT included") + intl.formatMessage({ + defaultMessage: "VAT included", + description: "vat included in order price" + }) ) : ( - i18n.t("does not apply") + intl.formatMessage({ + defaultMessage: "does not apply", + description: "vat not included in order price", + id: "orderPaymentVATDoesNotApply" + }) )} @@ -118,13 +141,22 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( - {i18n.t("Shipping")} + + + {maybe(() => order.shippingMethodName) === undefined && maybe(() => order.shippingPrice) === undefined ? ( ) : order.shippingMethodName === null ? ( - i18n.t("does not apply") + intl.formatMessage({ + defaultMessage: "does not apply", + description: "order does not require shipping", + id: "orderPaymentShippingDoesNotApply" + }) ) : ( order.shippingMethodName )} @@ -138,7 +170,12 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( - {i18n.t("Total")} + + + {maybe(() => order.total.gross) === undefined ? ( @@ -156,7 +193,12 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( - + - + - +
{i18n.t("Preauthorized amount")} + + {maybe(() => order.totalAuthorized.amount) === undefined ? ( @@ -166,7 +208,12 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })(
{i18n.t("Captured amount")} + + {maybe(() => order.totalCaptured.amount) === undefined ? ( @@ -176,7 +223,12 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })(
{i18n.t("Outstanding Balance")} + + {maybe( () => order.total.gross.amount && order.totalCaptured.amount @@ -202,22 +254,34 @@ const OrderPayment = withStyles(styles, { name: "OrderPayment" })( {canCapture && ( )} {canRefund && ( )} {canVoid && ( )} {canMarkAsPaid && ( )} diff --git a/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.tsx b/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.tsx index 5e9f8b068..a87536796 100644 --- a/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.tsx +++ b/src/orders/components/OrderPaymentDialog/OrderPaymentDialog.tsx @@ -5,12 +5,13 @@ 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 i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; export interface FormData { amount: number; @@ -32,58 +33,71 @@ const OrderPaymentDialog: React.StatelessComponent = ({ variant, onClose, onSubmit -}) => ( - -
{ - onSubmit(data); - onClose(); - }} - > - {({ data, change, submit }) => ( - <> - - {variant === "capture" - ? i18n.t("Capture payment", { context: "title" }) - : i18n.t("Refund payment", { context: "title" })} - +}) => { + const intl = useIntl(); - - - - - - { - onClose(); - submit(); - }} - > - {i18n.t("Confirm", { context: "button" })} - - - - )} -
-
-); + return ( + +
{ + onSubmit(data); + onClose(); + }} + > + {({ data, change, submit }) => ( + <> + + {variant === "capture" + ? intl.formatMessage({ + defaultMessage: "Capture Payment", + description: "dialog header" + }) + : intl.formatMessage({ + defaultMessage: "Refund Payment", + description: "dialog header" + })} + + + + + + + + { + onClose(); + submit(); + }} + > + + + + + )} +
+
+ ); +}; OrderPaymentDialog.displayName = "OrderPaymentDialog"; export default OrderPaymentDialog; diff --git a/src/orders/components/OrderPaymentVoidDialog/OrderPaymentVoidDialog.tsx b/src/orders/components/OrderPaymentVoidDialog/OrderPaymentVoidDialog.tsx index 28ae4a093..3dbd1a16a 100644 --- a/src/orders/components/OrderPaymentVoidDialog/OrderPaymentVoidDialog.tsx +++ b/src/orders/components/OrderPaymentVoidDialog/OrderPaymentVoidDialog.tsx @@ -5,11 +5,12 @@ import DialogContent from "@material-ui/core/DialogContent"; import DialogContentText from "@material-ui/core/DialogContentText"; import DialogTitle from "@material-ui/core/DialogTitle"; import React from "react"; +import { FormattedMessage } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; interface OrderPaymentVoidDialogProps { confirmButtonState: ConfirmButtonTransitionState; @@ -22,21 +23,28 @@ const OrderPaymentVoidDialog: React.StatelessComponent< OrderPaymentVoidDialogProps > = ({ confirmButtonState, open, onConfirm, onClose }) => ( - {i18n.t("Void payment", { context: "title" })} + + + - {i18n.t("Are you sure you want to void this payment?")} + - + - {i18n.t("Confirm", { context: "button" })} + diff --git a/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.tsx b/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.tsx index 7b5f4f557..479e2a567 100644 --- a/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.tsx +++ b/src/orders/components/OrderProductAddDialog/OrderProductAddDialog.tsx @@ -17,6 +17,7 @@ import TableRow from "@material-ui/core/TableRow"; import TextField from "@material-ui/core/TextField"; import React from "react"; import InfiniteScroll from "react-infinite-scroller"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import ConfirmButton, { @@ -25,7 +26,7 @@ import ConfirmButton, { import Money from "@saleor/components/Money"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; -import i18n from "@saleor/i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe, renderCollection } from "@saleor/misc"; import { FetchMoreProps } from "@saleor/types"; import { @@ -161,6 +162,7 @@ const OrderProductAddDialog = withStyles(styles, { onClose, onSubmit }: OrderProductAddDialogProps & WithStyles) => { + const intl = useIntl(); const [query, onQueryChange] = useSearchQuery(onFetch); const [variants, setVariants] = React.useState< SearchOrderVariant_products_edges_node_variants[] @@ -187,21 +189,24 @@ const OrderProductAddDialog = withStyles(styles, { fullWidth maxWidth="sm" > - {i18n.t("Add product")} + + +
{variant.name}
- {i18n.t("SKU {{ sku }}", { - sku: variant.sku - })} +
@@ -301,7 +310,7 @@ const OrderProductAddDialog = withStyles(styles, { () => ( - {i18n.t("No products matching given query")} + ) @@ -312,7 +321,7 @@ const OrderProductAddDialog = withStyles(styles, {
- {i18n.t("Confirm", { context: "button" })} + diff --git a/src/orders/components/OrderShippingMethodEditDialog/OrderShippingMethodEditDialog.tsx b/src/orders/components/OrderShippingMethodEditDialog/OrderShippingMethodEditDialog.tsx index d290f5f03..ab0d86ef7 100644 --- a/src/orders/components/OrderShippingMethodEditDialog/OrderShippingMethodEditDialog.tsx +++ b/src/orders/components/OrderShippingMethodEditDialog/OrderShippingMethodEditDialog.tsx @@ -10,6 +10,7 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState @@ -17,7 +18,7 @@ import ConfirmButton, { import Form from "@saleor/components/Form"; import Money from "@saleor/components/Money"; import { SingleSelectField } from "@saleor/components/SingleSelectField"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { OrderDetails_order_availableShippingMethods } from "../../types/OrderDetails"; export interface FormData { @@ -85,7 +86,10 @@ const OrderShippingMethodEditDialog = withStyles(styles, { return ( - {i18n.t("Edit shipping method", { context: "title" })} +
{({ change, data }) => ( @@ -100,7 +104,7 @@ const OrderShippingMethodEditDialog = withStyles(styles, { - {i18n.t("Confirm", { context: "button" })} + diff --git a/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.tsx b/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.tsx index ade726e67..147f578a6 100644 --- a/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.tsx +++ b/src/orders/components/OrderUnfulfilledItems/OrderUnfulfilledItems.tsx @@ -8,6 +8,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Money from "@saleor/components/Money"; @@ -16,7 +17,6 @@ import StatusLabel from "@saleor/components/StatusLabel"; import TableCellAvatar, { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { OrderDetails_order_lines } from "../../types/OrderDetails"; @@ -58,90 +58,116 @@ interface OrderUnfulfilledItemsProps extends WithStyles { const OrderUnfulfilledItems = withStyles(styles, { name: "OrderUnfulfilledItems" -})(({ canFulfill, classes, lines, onFulfill }: OrderUnfulfilledItemsProps) => ( - - line.quantity - line.quantityFulfilled) - .reduce((prev, curr) => prev + curr, 0) - })} - status="error" - /> - } - /> - - - - - {i18n.t("Product")} - - - {i18n.t("Quantity")} - - {i18n.t("Price")} - {i18n.t("Total")} - - - - {lines.map(line => ( - line.id)} - > - line.thumbnail.url)} - > - {maybe(() => line.productName) || } - +})(({ canFulfill, classes, lines, onFulfill }: OrderUnfulfilledItemsProps) => { + const intl = useIntl(); + + return ( + + line.quantity - line.quantityFulfilled) + .reduce((prev, curr) => prev + curr, 0) + } + )} + status="error" + /> + } + /> +
+ + + + + + + - {maybe(() => line.quantity - line.quantityFulfilled) || ( - - )} + - {maybe(() => line.unitPrice.gross) ? ( - - ) : ( - - )} + - {maybe( - () => - (line.quantity - line.quantityFulfilled) * - line.unitPrice.gross.amount - ) ? ( - - ) : ( - - )} + - ))} - -
- {canFulfill && ( - - - - )} -
-)); + + + {lines.map(line => ( + line.id)} + > + line.thumbnail.url)} + > + {maybe(() => line.productName) || } + + + {maybe(() => line.quantity - line.quantityFulfilled) || ( + + )} + + + {maybe(() => line.unitPrice.gross) ? ( + + ) : ( + + )} + + + {maybe( + () => + (line.quantity - line.quantityFulfilled) * + line.unitPrice.gross.amount + ) ? ( + + ) : ( + + )} + + + ))} + +
+ {canFulfill && ( + + + + )} +
+ ); +}); OrderUnfulfilledItems.displayName = "OrderUnfulfilledItems"; export default OrderUnfulfilledItems; diff --git a/src/orders/fixtures.ts b/src/orders/fixtures.ts index 706017967..4403c6939 100644 --- a/src/orders/fixtures.ts +++ b/src/orders/fixtures.ts @@ -1,3 +1,4 @@ +import { MessageDescriptor } from "react-intl"; import { SearchCustomers_customers_edges_node } from "../containers/SearchCustomers/types/SearchCustomers"; import { transformOrderStatus, transformPaymentStatus } from "../misc"; import { @@ -1126,8 +1127,12 @@ export const draftOrder = (placeholder: string): OrderDetails_order => ({ }); export const flatOrders = orders.map(order => ({ ...order, - orderStatus: transformOrderStatus(order.status), - paymentStatus: transformPaymentStatus(order.paymentStatus) + orderStatus: transformOrderStatus(order.status, { + formatMessage: (message: MessageDescriptor) => message.defaultMessage + } as any), + paymentStatus: transformPaymentStatus(order.paymentStatus, { + formatMessage: (message: MessageDescriptor) => message.defaultMessage + } as any) })); export const variants = [ { id: "p1", name: "Product 1: variant 1", sku: "12345", stockQuantity: 3 }, diff --git a/src/orders/index.tsx b/src/orders/index.tsx index 7dad19c21..8bf198769 100644 --- a/src/orders/index.tsx +++ b/src/orders/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { orderDraftListPath, OrderDraftListUrlQueryParams, @@ -46,15 +47,19 @@ const OrderDetails: React.StatelessComponent> = ({ ); }; -const Component = () => ( - <> - - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + ); +}; export default Component; diff --git a/src/orders/views/OrderDetails/OrderDetailsMessages.tsx b/src/orders/views/OrderDetails/OrderDetailsMessages.tsx index d24d7f741..809c7a48c 100644 --- a/src/orders/views/OrderDetails/OrderDetailsMessages.tsx +++ b/src/orders/views/OrderDetails/OrderDetailsMessages.tsx @@ -1,8 +1,8 @@ import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { OrderAddNote } from "../../types/OrderAddNote"; import { OrderCancel } from "../../types/OrderCancel"; @@ -52,55 +52,65 @@ export const OrderDetailsMessages: React.StatelessComponent< > = ({ children }) => { const navigate = useNavigator(); const pushMessage = useNotifier(); + const intl = useIntl(); const handlePaymentCapture = (data: OrderCapture) => { if (!maybe(() => data.orderCapture.errors.length)) { pushMessage({ - text: i18n.t("Payment successfully captured", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Payment successfully captured" }) }); } else { pushMessage({ - text: i18n.t("Payment not captured: {{ errorMessage }}", { - context: "notification", - errorMessage: data.orderCapture.errors.filter( - error => error.field === "payment" - )[0].message - }) + text: intl.formatMessage( + { + defaultMessage: "Payment not captured: {errorMessage}" + }, + { + errorMessage: data.orderCapture.errors.find( + error => error.field === "payment" + ).message + } + ) }); } }; const handlePaymentRefund = (data: OrderRefund) => { if (!maybe(() => data.orderRefund.errors.length)) { pushMessage({ - text: i18n.t("Payment successfully refunded", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Payment successfully refunded" }) }); } else { pushMessage({ - text: i18n.t("Payment not refunded: {{ errorMessage }}", { - context: "notification", - errorMessage: data.orderRefund.errors.filter( - error => error.field === "payment" - )[0].message - }) + text: intl.formatMessage( + { + defaultMessage: "Payment not refunded: {errorMessage}", + description: "notification" + }, + { + errorMessage: data.orderRefund.errors.find( + error => error.field === "payment" + ).message + } + ) }); } }; const handleOrderFulfillmentCreate = (data: OrderCreateFulfillment) => { if (!maybe(() => data.orderFulfillmentCreate.errors.length)) { pushMessage({ - text: i18n.t("Items successfully fulfilled", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Items successfully fulfilled" }) }); navigate(orderUrl(data.orderFulfillmentCreate.order.id), true); } else { pushMessage({ - text: i18n.t("Could not fulfill items", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not fulfill items" }) }); } @@ -108,53 +118,53 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleOrderMarkAsPaid = (data: OrderMarkAsPaid) => { if (!maybe(() => data.orderMarkAsPaid.errors.length)) { pushMessage({ - text: i18n.t("Order marked as paid", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order marked as paid" }) }); navigate(orderUrl(data.orderMarkAsPaid.order.id), true); } else { pushMessage({ - text: i18n.t("Could not mark order as paid", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not mark order as paid" }) }); } }; const handleOrderCancel = (data: OrderCancel) => { pushMessage({ - text: i18n.t("Order successfully cancelled", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order successfully cancelled" }) }); navigate(orderUrl(data.orderCancel.order.id), true); }; const handleDraftCancel = () => { pushMessage({ - text: i18n.t("Order successfully cancelled", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order successfully cancelled" }) }); navigate(orderListUrl(), true); }; const handleOrderVoid = () => { pushMessage({ - text: i18n.t("Order payment successfully voided", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order payment successfully voided" }) }); }; const handleNoteAdd = (data: OrderAddNote) => { if (!maybe(() => data.orderAddNote.errors.length)) { pushMessage({ - text: i18n.t("Note successfully added", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Note successfully added" }) }); } else { pushMessage({ - text: i18n.t("Could not add note", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not add note" }) }); } @@ -162,8 +172,8 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleUpdate = (data: OrderUpdate) => { if (!maybe(() => data.orderUpdate.errors.length)) { pushMessage({ - text: i18n.t("Order successfully updated", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order successfully updated" }) }); navigate(orderUrl(data.orderUpdate.order.id), true); @@ -172,8 +182,8 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleDraftUpdate = (data: OrderDraftUpdate) => { if (!maybe(() => data.draftOrderUpdate.errors.length)) { pushMessage({ - text: i18n.t("Order successfully updated", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order successfully updated" }) }); navigate(orderUrl(data.draftOrderUpdate.order.id), true); @@ -182,14 +192,14 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleShippingMethodUpdate = (data: OrderShippingMethodUpdate) => { if (!maybe(() => data.orderUpdateShipping.errors.length)) { pushMessage({ - text: i18n.t("Shipping method successfully updated", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Shipping method successfully updated" }) }); } else { pushMessage({ - text: i18n.t("Could not update shipping method", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not update shipping method" }) }); } @@ -198,14 +208,14 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleOrderLineDelete = (data: OrderLineDelete) => { if (!maybe(() => data.draftOrderLineDelete.errors.length)) { pushMessage({ - text: i18n.t("Order line deleted", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order line deleted" }) }); } else { pushMessage({ - text: i18n.t("Could not delete order line", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not delete order line" }) }); } @@ -213,15 +223,15 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleOrderLinesAdd = (data: OrderLinesAdd) => { if (!maybe(() => data.draftOrderLinesCreate.errors.length)) { pushMessage({ - text: i18n.t("Order line added", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order line added" }) }); navigate(orderUrl(data.draftOrderLinesCreate.order.id), true); } else { pushMessage({ - text: i18n.t("Could not create order line", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not create order line" }) }); } @@ -229,14 +239,14 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleOrderLineUpdate = (data: OrderLineUpdate) => { if (!maybe(() => data.draftOrderLineUpdate.errors.length)) { pushMessage({ - text: i18n.t("Order line updated", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Order line updated" }) }); } else { pushMessage({ - text: i18n.t("Could not update order line", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not update order line" }) }); } @@ -244,15 +254,15 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleOrderFulfillmentCancel = (data: OrderFulfillmentCancel) => { if (!maybe(() => data.orderFulfillmentCancel.errors.length)) { pushMessage({ - text: i18n.t("Fulfillment successfully cancelled", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Fulfillment successfully cancelled" }) }); navigate(orderUrl(data.orderFulfillmentCancel.order.id), true); } else { pushMessage({ - text: i18n.t("Could not cancel fulfillment", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not cancel fulfillment" }) }); } @@ -262,15 +272,15 @@ export const OrderDetailsMessages: React.StatelessComponent< ) => { if (!maybe(() => data.orderFulfillmentUpdateTracking.errors.length)) { pushMessage({ - text: i18n.t("Fulfillment successfully updated", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Fulfillment successfully updated" }) }); navigate(orderUrl(data.orderFulfillmentUpdateTracking.order.id), true); } else { pushMessage({ - text: i18n.t("Could not update fulfillment", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not update fulfillment" }) }); } @@ -278,15 +288,15 @@ export const OrderDetailsMessages: React.StatelessComponent< const handleDraftFinalize = (data: OrderDraftFinalize) => { if (!maybe(() => data.draftOrderComplete.errors.length)) { pushMessage({ - text: i18n.t("Draft order successfully finalized", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Draft order successfully finalized" }) }); navigate(orderUrl(data.draftOrderComplete.order.id), true); } else { pushMessage({ - text: i18n.t("Could not finalize draft", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Could not finalize draft" }) }); } diff --git a/src/orders/views/OrderDraftList.tsx b/src/orders/views/OrderDraftList.tsx index 129ba3fcf..635bbb7a2 100644 --- a/src/orders/views/OrderDraftList.tsx +++ b/src/orders/views/OrderDraftList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useBulkActions from "@saleor/hooks/useBulkActions"; @@ -11,7 +12,6 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; -import i18n from "@saleor/i18n"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import OrderDraftListPage from "../components/OrderDraftListPage"; @@ -44,6 +44,7 @@ export const OrderDraftList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.DRAFT_LIST ); + const intl = useIntl(); const closeModal = () => navigate( @@ -56,7 +57,9 @@ export const OrderDraftList: React.StatelessComponent = ({ const handleCreateOrderCreateSuccess = (data: OrderDraftCreate) => { notify({ - text: i18n.t("Order draft succesfully created") + text: intl.formatMessage({ + defaultMessage: "Order draft succesfully created" + }) }); navigate(orderUrl(data.draftOrderCreate.order.id)); }; @@ -77,7 +80,9 @@ export const OrderDraftList: React.StatelessComponent = ({ const handleOrderDraftBulkCancel = (data: OrderDraftBulkCancel) => { if (data.draftOrderBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed draft orders") + text: intl.formatMessage({ + defaultMessage: "Removed draft orders" + }) }); refetch(); reset(); @@ -145,22 +150,29 @@ export const OrderDraftList: React.StatelessComponent = ({ onClose={closeModal} onConfirm={onOrderDraftBulkDelete} open={params.action === "remove"} - title={i18n.t("Remove Order Drafts")} + title={intl.formatMessage({ + defaultMessage: "Delete Order Drafts", + description: "dialog header" + })} variant="delete" > - {{ number }} order drafts?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + ); diff --git a/src/orders/views/OrderList/OrderList.tsx b/src/orders/views/OrderList/OrderList.tsx index c099b6815..a8fe9c47b 100644 --- a/src/orders/views/OrderList/OrderList.tsx +++ b/src/orders/views/OrderList/OrderList.tsx @@ -1,5 +1,6 @@ import Button from "@material-ui/core/Button"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import SaveFilterTabDialog, { @@ -14,7 +15,6 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; -import i18n from "@saleor/i18n"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import OrderBulkCancelDialog from "../../components/OrderBulkCancelDialog"; @@ -62,6 +62,7 @@ export const OrderList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.ORDER_LIST ); + const intl = useIntl(); const tabs = getFilterTabs(); @@ -133,7 +134,9 @@ export const OrderList: React.StatelessComponent = ({ const handleCreateOrderCreateSuccess = (data: OrderDraftCreate) => { notify({ - text: i18n.t("Order draft succesfully created") + text: intl.formatMessage({ + defaultMessage: "Order draft succesfully created" + }) }); navigate(orderUrl(data.draftOrderCreate.order.id)); }; @@ -160,8 +163,8 @@ export const OrderList: React.StatelessComponent = ({ const handleOrderBulkCancel = (data: OrderBulkCancel) => { if (data.orderBulkCancel.errors.length === 0) { notify({ - text: i18n.t("Orders cancelled", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Orders cancelled" }) }); reset(); @@ -196,7 +199,8 @@ export const OrderList: React.StatelessComponent = ({ { formatDate }, - changeFilterField + changeFilterField, + intl )} currentTab={currentTab} disabled={loading} @@ -218,9 +222,10 @@ export const OrderList: React.StatelessComponent = ({ color="primary" onClick={() => openModal("cancel", listElements)} > - {i18n.t("Cancel", { - context: "cancel orders" - })} + } onSearchChange={email => changeFilterField({ email })} diff --git a/src/orders/views/OrderList/filters.ts b/src/orders/views/OrderList/filters.ts index 39bc73341..980a1119f 100644 --- a/src/orders/views/OrderList/filters.ts +++ b/src/orders/views/OrderList/filters.ts @@ -1,6 +1,7 @@ +import { defineMessages, IntlShape } from "react-intl"; + import { FilterContentSubmitData } from "../../../components/Filter"; import { Filter } from "../../../components/TableFilter"; -import i18n from "../../../i18n"; import { OrderFilterInput, OrderStatusFilter @@ -18,16 +19,43 @@ import { 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) { case OrderStatusFilter.FULFILLED.toString(): - return i18n.t("Fulfilled"); + return intl.formatMessage(filterMessages.fulfilled); case OrderStatusFilter.PARTIALLY_FULFILLED.toString(): - return i18n.t("Partially Fulfilled"); + return intl.formatMessage(filterMessages.partiallyFulfilled); case OrderStatusFilter.UNFULFILLED.toString(): - return i18n.t("Unfulfilled"); + return intl.formatMessage(filterMessages.unfulfilled); } return ""; @@ -90,7 +118,8 @@ interface OrderListChipFormatData { export function createFilterChips( filters: OrderListUrlFilters, formatData: OrderListChipFormatData, - onFilterDelete: (filters: OrderListUrlFilters) => void + onFilterDelete: (filters: OrderListUrlFilters) => void, + intl: IntlShape ): Filter[] { let filterChips: Filter[] = []; @@ -99,7 +128,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: i18n.t("Date is {{ date }}", { + label: intl.formatMessage(filterMessages.dateIs, { date: formatData.formatDate(filters.dateFrom) }), onClick: () => @@ -115,7 +144,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: i18n.t("Date from {{ date }}", { + label: intl.formatMessage(filterMessages.dateFrom, { date: formatData.formatDate(filters.dateFrom) }), onClick: () => @@ -131,7 +160,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: i18n.t("Date to {{ date }}", { + label: intl.formatMessage(filterMessages.dateTo, { date: formatData.formatDate(filters.dateTo) }), onClick: () => @@ -149,7 +178,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: getStatusLabel(filters.status), + label: getStatusLabel(filters.status, intl), onClick: () => onFilterDelete({ ...filters, diff --git a/src/pages/components/PageDetailsPage/PageDetailsPage.tsx b/src/pages/components/PageDetailsPage/PageDetailsPage.tsx index d55ad79e8..d3e3c7f4a 100644 --- a/src/pages/components/PageDetailsPage/PageDetailsPage.tsx +++ b/src/pages/components/PageDetailsPage/PageDetailsPage.tsx @@ -5,6 +5,7 @@ import { RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -16,7 +17,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { UserError } from "../../../types"; import { PageDetails_page } from "../../types/PageDetails"; @@ -52,6 +53,8 @@ const PageDetailsPage: React.StatelessComponent = ({ onRemove, onSubmit }) => { + const intl = useIntl(); + const initialForm: FormData = { content: maybe( () => JSON.parse(page.contentJson), @@ -68,12 +71,15 @@ const PageDetailsPage: React.StatelessComponent = ({ {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Pages")} + + {intl.formatMessage(sectionNames.pages)} + page.title) } @@ -99,9 +105,10 @@ const PageDetailsPage: React.StatelessComponent = ({ onChange={change} title={data.seoTitle} titlePlaceholder={data.title} - helperText={i18n.t( - "Add search engine title and description to make this page easier to find" - )} + helperText={intl.formatMessage({ + defaultMessage: + "Add search engine title and description to make this page easier to find" + })} />
diff --git a/src/pages/components/PageInfo/PageInfo.tsx b/src/pages/components/PageInfo/PageInfo.tsx index db53dcb7e..955aa6892 100644 --- a/src/pages/components/PageInfo/PageInfo.tsx +++ b/src/pages/components/PageInfo/PageInfo.tsx @@ -3,11 +3,12 @@ import CardContent from "@material-ui/core/CardContent"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import FormSpacer from "@saleor/components/FormSpacer"; import RichTextEditor from "@saleor/components/RichTextEditor"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { maybe } from "../../../misc"; import { FormErrors } from "../../../types"; import { PageDetails_page } from "../../types/PageDetails"; @@ -37,33 +38,45 @@ const PageInfo = withStyles(styles, { errors, page, onChange - }: PageInfoProps & WithStyles) => ( - - - - ) => { + const intl = useIntl(); + + return ( + + - - JSON.parse(page.contentJson))} - label={i18n.t("Content")} - name={"content" as keyof FormData} - onChange={onChange} - /> - - - ) + + + + JSON.parse(page.contentJson))} + label={intl.formatMessage({ + defaultMessage: "Content", + description: "page content" + })} + name={"content" as keyof FormData} + onChange={onChange} + /> + + + ); + } ); PageInfo.displayName = "PageInfo"; export default PageInfo; diff --git a/src/pages/components/PageList/PageList.tsx b/src/pages/components/PageList/PageList.tsx index dc3ac0b36..7af2fa53d 100644 --- a/src/pages/components/PageList/PageList.tsx +++ b/src/pages/components/PageList/PageList.tsx @@ -11,13 +11,13 @@ import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection } from "@saleor/misc"; import { ListActions, ListProps } from "@saleor/types"; import { PageList_pages_edges_node } from "../../types/PageList"; @@ -63,100 +63,121 @@ const PageList = withStyles(styles, { name: "PageList" })( toggle, toggleAll, toolbar - }: PageListProps & WithStyles) => ( - - - - - {i18n.t("Title", { context: "table header" })} - - - {i18n.t("Slug", { context: "table header" })} - - - {i18n.t("Visibility", { context: "table header" })} - - - - - - - - - {renderCollection( - pages, - page => { - const isSelected = page ? isChecked(page.id) : false; + }: PageListProps & WithStyles) => { + const intl = useIntl(); - return ( - - - toggle(page.id)} - /> - - - {maybe(() => page.title, )} - - - {maybe(() => page.slug, )} - - - {maybe( - () => ( - - ), - - )} + return ( + +
+ + + + + + + + + + + + + + + + + + {renderCollection( + pages, + page => { + const isSelected = page ? isChecked(page.id) : false; + + return ( + + + toggle(page.id)} + /> + + + {maybe(() => page.title, )} + + + {maybe(() => page.slug, )} + + + {maybe( + () => ( + + ), + + )} + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No pages found")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); PageList.displayName = "PageList"; export default PageList; diff --git a/src/pages/components/PageListPage/PageListPage.tsx b/src/pages/components/PageListPage/PageListPage.tsx index 282058a50..a3342a55d 100644 --- a/src/pages/components/PageListPage/PageListPage.tsx +++ b/src/pages/components/PageListPage/PageListPage.tsx @@ -1,11 +1,12 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { PageList_pages_edges_node } from "../../types/PageList"; import PageList from "../PageList/PageList"; @@ -31,36 +32,42 @@ const PageListPage: React.StatelessComponent = ({ toggle, toggleAll, toolbar -}) => ( - - {i18n.t("Configuration")} - - + + - {i18n.t("Add page")} - - - - - -); + settings={settings} + pages={pages} + onNextPage={onNextPage} + onPreviousPage={onPreviousPage} + onUpdateListSettings={onUpdateListSettings} + onRowClick={onRowClick} + pageInfo={pageInfo} + isChecked={isChecked} + selected={selected} + toggle={toggle} + toggleAll={toggleAll} + toolbar={toolbar} + /> + + ); +}; PageListPage.displayName = "PageListPage"; export default PageListPage; diff --git a/src/pages/components/PageSlug/PageSlug.tsx b/src/pages/components/PageSlug/PageSlug.tsx index 0cfa9c7ba..fded6707c 100644 --- a/src/pages/components/PageSlug/PageSlug.tsx +++ b/src/pages/components/PageSlug/PageSlug.tsx @@ -2,10 +2,10 @@ 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 { useIntl } from "react-intl"; import slugify from "slugify"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; import { FormData } from "../PageDetailsPage"; export interface PageSlugProps { @@ -20,26 +20,40 @@ const PageSlug: React.StatelessComponent = ({ disabled, errors, onChange -}) => ( - - - - { + const intl = useIntl(); + + return ( + + - - -); + + + + + ); +}; PageSlug.displayName = "PageSlug"; export default PageSlug; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index e45c1b49f..aacc211ec 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { pageCreatePath, pageListPath, @@ -37,15 +38,19 @@ const PageDetails: React.StatelessComponent> = ({ ); }; -const Component = () => ( - <> - - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + ); +}; export default Component; diff --git a/src/pages/views/PageCreate.tsx b/src/pages/views/PageCreate.tsx index 615deab40..38e8d83fd 100644 --- a/src/pages/views/PageCreate.tsx +++ b/src/pages/views/PageCreate.tsx @@ -1,9 +1,9 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import PageDetailsPage from "../components/PageDetailsPage"; import { TypedPageCreate } from "../mutations"; @@ -17,12 +17,13 @@ export interface PageCreateProps { export const PageCreate: React.StatelessComponent = () => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handlePageCreate = (data: PageCreateData) => { if (data.pageCreate.errors.length === 0) { notify({ - text: i18n.t("Successfully created new page", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Successfully created new page" }) }); navigate(pageUrl(data.pageCreate.page.id)); @@ -40,7 +41,12 @@ export const PageCreate: React.StatelessComponent = () => { return ( <> - + pageCreateOpts.data.pageCreate.errors, [])} diff --git a/src/pages/views/PageDetails.tsx b/src/pages/views/PageDetails.tsx index 90d0e1b00..066554652 100644 --- a/src/pages/views/PageDetails.tsx +++ b/src/pages/views/PageDetails.tsx @@ -1,11 +1,11 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import { PageInput } from "../../types/globalTypes"; import PageDetailsPage, { FormData } from "../components/PageDetailsPage"; @@ -45,12 +45,13 @@ export const PageDetails: React.StatelessComponent = ({ }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handlePageRemove = (data: PageRemove) => { if (data.pageDelete.errors.length === 0) { notify({ - text: i18n.t("Removed page", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Removed page" }) }); navigate(pageListUrl()); @@ -107,25 +108,30 @@ export const PageDetails: React.StatelessComponent = ({ navigate(pageUrl(id))} onConfirm={pageRemove} variant="delete" > - {{ title }}?", - { - context: "page remove", - title: maybe( - () => pageDetails.data.page.title, - "..." - ) - } - ) - }} - /> + + + {maybe( + () => pageDetails.data.page.title, + "..." + )} + + ) + }} + /> + ); diff --git a/src/pages/views/PageList.tsx b/src/pages/views/PageList.tsx index 7bc199c22..511a00d6c 100644 --- a/src/pages/views/PageList.tsx +++ b/src/pages/views/PageList.tsx @@ -3,6 +3,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { configurationMenuUrl } from "@saleor/configuration"; @@ -13,7 +14,6 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; -import i18n from "@saleor/i18n"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import PageListPage from "../components/PageListPage/PageListPage"; @@ -45,6 +45,8 @@ export const PageList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.PAGES_LIST ); + const intl = useIntl(); + const paginationState = createPaginationState(settings.rowNumber, params); return ( @@ -79,7 +81,10 @@ export const PageList: React.StatelessComponent = ({ if (data.pageBulkPublish.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Published pages") + text: intl.formatMessage({ + defaultMessage: "Published pages", + description: "notification" + }) }); reset(); refetch(); @@ -90,7 +95,10 @@ export const PageList: React.StatelessComponent = ({ if (data.pageBulkDelete.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Removed pages") + text: intl.formatMessage({ + defaultMessage: "Removed pages", + description: "notification" + }) }); reset(); refetch(); @@ -137,13 +145,19 @@ export const PageList: React.StatelessComponent = ({ openModal("unpublish", listElements) } > - {i18n.t("Unpublish")} + = ({ } }) } - title={i18n.t("Publish pages")} + title={intl.formatMessage({ + defaultMessage: "Publish Pages", + description: "dialog header" + })} > - {{ number }} pages?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + = ({ } }) } - title={i18n.t("Unpublish pages")} + title={intl.formatMessage({ + defaultMessage: "Unpublish Pages", + description: "dialog header" + })} > - {{ number }} pages?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} ) }} /> @@ -226,18 +250,21 @@ export const PageList: React.StatelessComponent = ({ }) } variant="delete" - title={i18n.t("Remove pages")} + title={intl.formatMessage({ + defaultMessage: "Delete Pages", + description: "dialog header" + })} > - {{ number }} pages?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} ) }} /> diff --git a/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.tsx b/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.tsx index add4b20ff..a8ba7c5d2 100644 --- a/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.tsx +++ b/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.tsx @@ -15,6 +15,7 @@ import Typography from "@material-ui/core/Typography"; import makeStyles from "@material-ui/styles/makeStyles"; import React from "react"; import InfiniteScroll from "react-infinite-scroller"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import ConfirmButton, { @@ -23,7 +24,7 @@ import ConfirmButton, { import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; -import i18n from "@saleor/i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe, renderCollection } from "@saleor/misc"; import { FetchMoreProps } from "@saleor/types"; import { SearchAttributes_productType_availableAttributes_edges_node } from "../../containers/SearchAttributes/types/SearchAttributes"; @@ -73,6 +74,7 @@ const AssignAttributeDialog: React.FC = ({ onSubmit, onToggle }: AssignAttributeDialogProps) => { + const intl = useIntl(); const classes = useStyles({}); const [query, onQueryChange, resetQuery] = useSearchQuery(onFetch); const errors = useModalDialogErrors(apiErrors, open); @@ -84,17 +86,22 @@ const AssignAttributeDialog: React.FC = ({ return ( - {i18n.t("Assign Attribute")} + + + = ({ !loading && ( - {i18n.t("No results found")} + ) @@ -173,7 +180,7 @@ const AssignAttributeDialog: React.FC = ({ )} = ({ type="submit" onClick={onSubmit} > - {i18n.t("Assign attributes", { context: "button" })} + diff --git a/src/productTypes/components/ProductTypeAttributeEditDialog/ProductTypeAttributeEditDialog.tsx b/src/productTypes/components/ProductTypeAttributeEditDialog/ProductTypeAttributeEditDialog.tsx index e275ed5c8..00e1b7f63 100644 --- a/src/productTypes/components/ProductTypeAttributeEditDialog/ProductTypeAttributeEditDialog.tsx +++ b/src/productTypes/components/ProductTypeAttributeEditDialog/ProductTypeAttributeEditDialog.tsx @@ -5,11 +5,12 @@ 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 Form from "@saleor/components/Form"; import { FormSpacer } from "@saleor/components/FormSpacer"; import ListField from "@saleor/components/ListField"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; export interface FormData { name: string; @@ -39,6 +40,8 @@ export interface ProductTypeAttributeEditDialogProps { const ProductTypeAttributeEditDialog: React.StatelessComponent< ProductTypeAttributeEditDialogProps > = ({ disabled, errors, name, opened, title, values, onClose, onConfirm }) => { + const intl = useIntl(); + const initialForm: FormData = { name: name || "", values: values || [] @@ -54,7 +57,9 @@ const ProductTypeAttributeEditDialog: React.StatelessComponent< disabled={disabled} error={!!formErrors.name} fullWidth - label={i18n.t("Attribute name")} + label={intl.formatMessage({ + defaultMessage: "Attribute name" + })} helperText={formErrors.name} name="name" value={data.name} @@ -71,7 +76,9 @@ const ProductTypeAttributeEditDialog: React.StatelessComponent< } fullWidth name="values" - label={i18n.t("Attribute values")} + label={intl.formatMessage({ + defaultMessage: "Attribute values" + })} helperText={ formErrors.values || formErrors.addValues || @@ -83,10 +90,10 @@ const ProductTypeAttributeEditDialog: React.StatelessComponent< diff --git a/src/productTypes/components/ProductTypeAttributeUnassignDialog/ProductTypeAttributeUnassignDialog.tsx b/src/productTypes/components/ProductTypeAttributeUnassignDialog/ProductTypeAttributeUnassignDialog.tsx index e99ce0a0c..5a1f2e077 100644 --- a/src/productTypes/components/ProductTypeAttributeUnassignDialog/ProductTypeAttributeUnassignDialog.tsx +++ b/src/productTypes/components/ProductTypeAttributeUnassignDialog/ProductTypeAttributeUnassignDialog.tsx @@ -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 ProductTypeAttributeUnassignDialogProps { attributeName: string; @@ -23,27 +23,32 @@ const ProductTypeAttributeUnassignDialog: React.FC< productTypeName, onClose, onConfirm -}) => ( - - {{ attributeName }} from {{ productTypeName }}?", - { - attributeName, - productTypeName - } - ) - }} - /> - -); +}) => { + const intl = useIntl(); + + return ( + + + {attributeName}, + productTypeName: {productTypeName} + }} + /> + + + ); +}; ProductTypeAttributeUnassignDialog.displayName = "ProductTypeAttributeUnassignDialog"; export default ProductTypeAttributeUnassignDialog; diff --git a/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.tsx b/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.tsx index 99087212c..5dd83dc41 100644 --- a/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.tsx +++ b/src/productTypes/components/ProductTypeAttributes/ProductTypeAttributes.tsx @@ -12,6 +12,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Checkbox from "@saleor/components/Checkbox"; @@ -21,7 +22,6 @@ import { SortableTableRow } from "@saleor/components/SortableTable"; import TableHead from "@saleor/components/TableHead"; -import i18n from "@saleor/i18n"; import { maybe, renderCollection, stopPropagation } from "@saleor/misc"; import { ListActions, ReorderAction } from "@saleor/types"; import { AttributeTypeEnum } from "@saleor/types/globalTypes"; @@ -81,105 +81,123 @@ const ProductTypeAttributes = withStyles(styles, { onAttributeClick, onAttributeReorder, onAttributeUnassign - }: ProductTypeAttributesProps & WithStyles) => ( - - onAttributeAssign(AttributeTypeEnum[type])} - > - {i18n.t("Assign attribute", { context: "button" })} - - } - /> - - - - {i18n.t("Attribute name")} - - {i18n.t("Slug")} - - - - {renderCollection( - attributes, - (attribute, attributeIndex) => { - const isSelected = attribute ? isChecked(attribute.id) : false; + }: ProductTypeAttributesProps & WithStyles) => { + const intl = useIntl(); - return ( - onAttributeClick(attribute.id) - : undefined - } - key={maybe(() => attribute.id)} - index={attributeIndex || 0} - > - - toggle(attribute.id)} - /> - - - {maybe(() => attribute.name) ? ( - attribute.name - ) : ( - - )} - - - {maybe(() => attribute.slug) ? ( - attribute.slug - ) : ( - - )} - - - - onAttributeUnassign(attribute.id) + return ( + + onAttributeAssign(AttributeTypeEnum[type])} + > + + + } + /> +
+ + + + + + + + + + + {renderCollection( + attributes, + (attribute, attributeIndex) => { + const isSelected = attribute ? isChecked(attribute.id) : false; + + return ( + onAttributeClick(attribute.id) + : undefined + } + key={maybe(() => attribute.id)} + index={attributeIndex || 0} + > + + toggle(attribute.id)} + /> + + + {maybe(() => attribute.name) ? ( + attribute.name + ) : ( + )} - > - - + + + {maybe(() => attribute.slug) ? ( + attribute.slug + ) : ( + + )} + + + + onAttributeUnassign(attribute.id) + )} + > + + + + + ); + }, + () => ( + + + - - ); - }, - () => ( - - - {i18n.t("No attributes found")} - - - ) - )} - -
-
- ) + + ) + )} + + + + ); + } ); ProductTypeAttributes.displayName = "ProductTypeAttributes"; export default ProductTypeAttributes; diff --git a/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.tsx b/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.tsx index 0f73c08c4..7f0de5fd4 100644 --- a/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.tsx +++ b/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.tsx @@ -1,12 +1,12 @@ 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 ProductTypeBulkAttributeUnassignDialogProps { - attributeQuantity: string; + attributeQuantity: number; confirmButtonState: ConfirmButtonTransitionState; open: boolean; productTypeName: string; @@ -23,27 +23,37 @@ const ProductTypeBulkAttributeUnassignDialog: React.FC< productTypeName, onClose, onConfirm -}) => ( - - {{ attributeQuantity }} attributes from {{ productTypeName }}?", - { - attributeQuantity, - productTypeName - } - ) - }} - /> - -); +}) => { + const intl = useIntl(); + + return ( + + + {attributeQuantity}, + counter: attributeQuantity, + productTypeName: {productTypeName} + }} + /> + + + ); +}; ProductTypeBulkAttributeUnassignDialog.displayName = "ProductTypeBulkAttributeUnassignDialog"; export default ProductTypeBulkAttributeUnassignDialog; diff --git a/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx b/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx index 10ce39d20..fd639bad6 100644 --- a/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx +++ b/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -10,7 +11,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ChangeEvent, FormChange } from "@saleor/hooks/useForm"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ProductTypeDetails_taxTypes } from "@saleor/productTypes/types/ProductTypeDetails"; import { UserError } from "@saleor/types"; import { WeightUnitsEnum } from "@saleor/types/globalTypes"; @@ -67,6 +68,7 @@ const ProductTypeCreatePage: React.StatelessComponent< onBack, onSubmit }: ProductTypeCreatePageProps) => { + const intl = useIntl(); const [taxTypeDisplayName, setTaxTypeDisplayName] = useStateFromProps(""); return ( @@ -78,7 +80,9 @@ const ProductTypeCreatePage: React.StatelessComponent< > {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Product Types")} + + {intl.formatMessage(sectionNames.productTypes)} +
diff --git a/src/productTypes/components/ProductTypeDeleteDialog/ProductTypeDeleteDialog.tsx b/src/productTypes/components/ProductTypeDeleteDialog/ProductTypeDeleteDialog.tsx index 56d42e316..fa64b7e1f 100644 --- a/src/productTypes/components/ProductTypeDeleteDialog/ProductTypeDeleteDialog.tsx +++ b/src/productTypes/components/ProductTypeDeleteDialog/ProductTypeDeleteDialog.tsx @@ -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 ProductTypeDeleteDialogProps { confirmButtonState: ConfirmButtonTransitionState; @@ -19,25 +19,31 @@ const ProductTypeDeleteDialog: React.FC = ({ name, onClose, onConfirm -}) => ( - - {{ name }}?", - { - name - } - ) - }} - /> - -); +}) => { + const intl = useIntl(); + + return ( + + + {name} + }} + /> + + + ); +}; ProductTypeDeleteDialog.displayName = "ProductTypeDeleteDialog"; export default ProductTypeDeleteDialog; diff --git a/src/productTypes/components/ProductTypeDetails/ProductTypeDetails.tsx b/src/productTypes/components/ProductTypeDetails/ProductTypeDetails.tsx index dfe12c937..6a9d6643d 100644 --- a/src/productTypes/components/ProductTypeDetails/ProductTypeDetails.tsx +++ b/src/productTypes/components/ProductTypeDetails/ProductTypeDetails.tsx @@ -3,9 +3,10 @@ import CardContent from "@material-ui/core/CardContent"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; import { FormErrors } from "@saleor/types"; const styles = createStyles({ @@ -24,23 +25,31 @@ interface ProductTypeDetailsProps extends WithStyles { } const ProductTypeDetails = withStyles(styles, { name: "ProductTypeDetails" })( - ({ classes, data, disabled, errors, onChange }: ProductTypeDetailsProps) => ( - - - - { + const intl = useIntl(); + + return ( + + - - - ) + + + + + ); + } ); ProductTypeDetails.displayName = "ProductTypeDetails"; export default ProductTypeDetails; diff --git a/src/productTypes/components/ProductTypeDetailsPage/ProductTypeDetailsPage.tsx b/src/productTypes/components/ProductTypeDetailsPage/ProductTypeDetailsPage.tsx index e0193475f..2b4bfb9af 100644 --- a/src/productTypes/components/ProductTypeDetailsPage/ProductTypeDetailsPage.tsx +++ b/src/productTypes/components/ProductTypeDetailsPage/ProductTypeDetailsPage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -11,7 +12,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ChangeEvent, FormChange } from "@saleor/hooks/useForm"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { ListActions, ReorderEvent, UserError } from "@saleor/types"; import { AttributeTypeEnum, WeightUnitsEnum } from "@saleor/types/globalTypes"; @@ -90,6 +91,7 @@ const ProductTypeDetailsPage: React.StatelessComponent< onDelete, onSubmit }) => { + const intl = useIntl(); const [taxTypeDisplayName, setTaxTypeDisplayName] = useStateFromProps( maybe(() => productType.taxType.description) ); @@ -129,7 +131,9 @@ const ProductTypeDetailsPage: React.StatelessComponent< > {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Product Types")} + + {intl.formatMessage(sectionNames.productTypes)} +
@@ -171,7 +175,10 @@ const ProductTypeDetailsPage: React.StatelessComponent< diff --git a/src/productTypes/components/ProductTypeList/ProductTypeList.tsx b/src/productTypes/components/ProductTypeList/ProductTypeList.tsx index 1e2fdfc5a..afb28f5b6 100644 --- a/src/productTypes/components/ProductTypeList/ProductTypeList.tsx +++ b/src/productTypes/components/ProductTypeList/ProductTypeList.tsx @@ -12,12 +12,12 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } 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 "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ListActions, ListProps } from "../../../types"; import { ProductTypeList_productTypes_edges_node } from "../../types/ProductTypeList"; @@ -64,115 +64,144 @@ const ProductTypeList = withStyles(styles, { name: "ProductTypeList" })( toggle, toggleAll, toolbar - }: ProductTypeListProps) => ( - - - - - {i18n.t("Type Name", { context: "table header" })} - - - {i18n.t("Type", { context: "table header" })} - - - {i18n.t("Tax", { context: "table header" })} - - - - - - - - - {renderCollection( - productTypes, - productType => { - const isSelected = productType - ? isChecked(productType.id) - : false; - return ( - - - toggle(productType.id)} - /> - - - {productType ? ( - <> - {productType.name} - - {maybe(() => productType.hasVariants) - ? i18n.t("Configurable", { - context: "product type" - }) - : i18n.t("Simple product", { - context: "product type" - })} - - - ) : ( - - )} - - - {maybe(() => productType.isShippingRequired) !== - undefined ? ( - productType.isShippingRequired ? ( - <>{i18n.t("Physical", { context: "product type" })} + }: ProductTypeListProps) => { + const intl = useIntl(); + + return ( + +
+ + + + + + + + + + + + + + + + + + {renderCollection( + productTypes, + productType => { + const isSelected = productType + ? isChecked(productType.id) + : false; + return ( + + + toggle(productType.id)} + /> + + + {productType ? ( + <> + {productType.name} + + {maybe(() => productType.hasVariants) + ? intl.formatMessage({ + defaultMessage: "Configurable", + description: "product type" + }) + : intl.formatMessage({ + defaultMessage: "Simple product", + description: "product type" + })} + + ) : ( - <>{i18n.t("Digital", { context: "product type" })} - ) - ) : ( - - )} - - - {maybe(() => productType.taxType) ? ( - productType.taxType.description - ) : ( - - )} + + )} + + + {maybe(() => productType.isShippingRequired) !== + undefined ? ( + productType.isShippingRequired ? ( + <> + + + ) : ( + <> + + + ) + ) : ( + + )} + + + {maybe(() => productType.taxType) ? ( + productType.taxType.description + ) : ( + + )} + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No product types found")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); ProductTypeList.displayName = "ProductTypeList"; export default ProductTypeList; diff --git a/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx b/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx index 67d130f2e..be7a96916 100644 --- a/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx +++ b/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx @@ -1,11 +1,12 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "../../../types"; import { ProductTypeList_productTypes_edges_node } from "../../types/ProductTypeList"; import ProductTypeList from "../ProductTypeList"; @@ -17,21 +18,31 @@ interface ProductTypeListPageProps extends PageListProps, ListActions { const ProductTypeListPage: React.StatelessComponent< ProductTypeListPageProps -> = ({ disabled, onAdd, onBack, ...listProps }) => ( - - {i18n.t("Configuration")} - - - - - -); +> = ({ disabled, onAdd, onBack, ...listProps }) => { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.configuration)} + + + + + + + ); +}; ProductTypeListPage.displayName = "ProductTypeListPage"; export default ProductTypeListPage; diff --git a/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.tsx b/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.tsx index be0b5daa2..df400dbed 100644 --- a/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.tsx +++ b/src/productTypes/components/ProductTypeShipping/ProductTypeShipping.tsx @@ -2,10 +2,10 @@ 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 { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox"; -import i18n from "../../../i18n"; import { WeightUnitsEnum } from "../../../types/globalTypes"; interface ProductTypeShippingProps { @@ -20,34 +20,49 @@ interface ProductTypeShippingProps { const ProductTypeShipping: React.StatelessComponent< ProductTypeShippingProps -> = ({ data, defaultWeightUnit, disabled, onChange }) => ( - - - - = ({ data, defaultWeightUnit, disabled, onChange }) => { + const intl = useIntl(); + + return ( + + - {data.isShippingRequired && ( - + - )} - - -); + {data.isShippingRequired && ( + + )} + + + ); +}; ProductTypeShipping.displayName = "ProductTypeShipping"; export default ProductTypeShipping; diff --git a/src/productTypes/components/ProductTypeTaxes/ProductTypeTaxes.tsx b/src/productTypes/components/ProductTypeTaxes/ProductTypeTaxes.tsx index a03edfd79..3b2985c9a 100644 --- a/src/productTypes/components/ProductTypeTaxes/ProductTypeTaxes.tsx +++ b/src/productTypes/components/ProductTypeTaxes/ProductTypeTaxes.tsx @@ -2,11 +2,11 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField"; import { ProductTypeDetails_taxTypes } from "@saleor/productTypes/types/ProductTypeDetails"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { ProductTypeForm } from "../ProductTypeDetailsPage/ProductTypeDetailsPage"; @@ -34,29 +34,42 @@ const ProductTypeTaxes = withStyles(styles, { name: "ProductTypeTaxes" })( taxTypes, taxTypeDisplayName, onChange - }: ProductTypeTaxesProps) => ( - - - - - taxTypes.map(c => ({ label: c.description, value: c.taxCode })), - [] - )} - InputProps={{ - autoComplete: "off" - }} + }: ProductTypeTaxesProps) => { + const intl = useIntl(); + + return ( + + - - - ) + + + taxTypes.map(c => ({ label: c.description, value: c.taxCode })), + [] + )} + InputProps={{ + autoComplete: "off" + }} + /> + + + ); + } ); ProductTypeTaxes.displayName = "ProductTypeTaxes"; export default ProductTypeTaxes; diff --git a/src/productTypes/index.tsx b/src/productTypes/index.tsx index b80cb3dcf..dbde2f8f0 100644 --- a/src/productTypes/index.tsx +++ b/src/productTypes/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { productTypeAddPath, productTypeListPath, @@ -40,17 +41,19 @@ const ProductTypeUpdate: React.StatelessComponent< ); }; -export const ProductTypeRouter: React.StatelessComponent< - RouteComponentProps -> = () => ( - <> - - - - - - - -); +export const ProductTypeRouter: React.FC = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + ); +}; ProductTypeRouter.displayName = "ProductTypeRouter"; export default ProductTypeRouter; diff --git a/src/productTypes/views/ProductTypeCreate.tsx b/src/productTypes/views/ProductTypeCreate.tsx index 2427377f1..0030d5248 100644 --- a/src/productTypes/views/ProductTypeCreate.tsx +++ b/src/productTypes/views/ProductTypeCreate.tsx @@ -1,9 +1,9 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import ProductTypeCreatePage, { ProductTypeForm @@ -16,11 +16,14 @@ import { productTypeListUrl, productTypeUrl } from "../urls"; export const ProductTypeCreate: React.StatelessComponent = () => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleCreateSuccess = (updateData: ProductTypeCreateMutation) => { if (updateData.productTypeCreate.errors.length === 0) { notify({ - text: i18n.t("Successfully created product type") + text: intl.formatMessage({ + defaultMessage: "Successfully created product type" + }) }); navigate(productTypeUrl(updateData.productTypeCreate.productType.id)); } @@ -48,7 +51,13 @@ export const ProductTypeCreate: React.StatelessComponent = () => { {({ data, loading }) => ( <> - + data.shop.defaultWeightUnit)} disabled={loading} @@ -57,8 +66,10 @@ export const ProductTypeCreate: React.StatelessComponent = () => { ? createProductTypeData.productTypeCreate.errors : undefined } - pageTitle={i18n.t("Create Product Type", { - context: "page title" + pageTitle={intl.formatMessage({ + defaultMessage: "Create Product Type", + description: "header", + id: "productTypeCreatePageHeader" })} saveButtonBarState={formTransitionState} taxTypes={maybe(() => data.taxTypes, [])} diff --git a/src/productTypes/views/ProductTypeList.tsx b/src/productTypes/views/ProductTypeList.tsx index 101b9fc26..ca83ccc45 100644 --- a/src/productTypes/views/ProductTypeList.tsx +++ b/src/productTypes/views/ProductTypeList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useBulkActions from "@saleor/hooks/useBulkActions"; @@ -10,9 +11,9 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; +import { commonMessages } from "@saleor/intl"; import { PAGINATE_BY } from "../../config"; import { configurationMenuUrl } from "../../configuration"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import ProductTypeListPage from "../components/ProductTypeListPage"; import { TypedProductTypeBulkDeleteMutation } from "../mutations"; @@ -38,6 +39,7 @@ export const ProductTypeList: React.StatelessComponent< const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); + const intl = useIntl(); const closeModal = () => navigate(productTypeListUrl(), true); @@ -54,7 +56,7 @@ export const ProductTypeList: React.StatelessComponent< const handleProductTypeBulkDelete = (data: ProductTypeBulkDelete) => { if (data.productTypeBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed product types") + text: intl.formatMessage(commonMessages.savedChanges) }); reset(); refetch(); @@ -126,22 +128,27 @@ export const ProductTypeList: React.StatelessComponent< onClose={closeModal} onConfirm={onProductTypeBulkDelete} open={params.action === "remove"} - title={i18n.t("Remove Product Types")} + title={intl.formatMessage({ + defaultMessage: "Delete Product Types", + description: "dialog header" + })} variant="delete" > - {{ number }} product types?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + {maybe(() => params.ids.length)} + ) + }} + /> + ); diff --git a/src/productTypes/views/ProductTypeUpdate/index.tsx b/src/productTypes/views/ProductTypeUpdate/index.tsx index 1e59ccb7c..67f94a381 100644 --- a/src/productTypes/views/ProductTypeUpdate/index.tsx +++ b/src/productTypes/views/ProductTypeUpdate/index.tsx @@ -1,12 +1,13 @@ import Button from "@material-ui/core/Button"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import { attributeUrl } from "@saleor/attributes/urls"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useBulkActions from "@saleor/hooks/useBulkActions"; 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 AssignAttributeDialog from "@saleor/productTypes/components/AssignAttributeDialog"; import { ReorderEvent } from "@saleor/types"; @@ -44,6 +45,7 @@ export const ProductTypeUpdate: React.FC = ({ const notify = useNotifier(); const productAttributeListActions = useBulkActions(); const variantAttributeListActions = useBulkActions(); + const intl = useIntl(); return ( @@ -59,9 +61,7 @@ export const ProductTypeUpdate: React.FC = ({ const handleAttributeAssignSuccess = (data: AssignAttribute) => { if (data.attributeAssign.errors.length === 0) { notify({ - text: i18n.t("Attributes assigned", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); } else if ( @@ -76,9 +76,7 @@ export const ProductTypeUpdate: React.FC = ({ ) => { if (data.attributeUnassign.errors.length === 0) { notify({ - text: i18n.t("Attribute unassigned", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); productAttributeListActions.reset(); @@ -90,8 +88,8 @@ export const ProductTypeUpdate: React.FC = ({ ) => { if (deleteData.productTypeDelete.errors.length === 0) { notify({ - text: i18n.t("Product type deleted", { - context: "notification" + text: intl.formatMessage({ + defaultMessage: "Product type deleted" }) }); navigate(productTypeListUrl(), true); @@ -105,9 +103,7 @@ export const ProductTypeUpdate: React.FC = ({ updateData.productTypeUpdate.errors.length === 0 ) { notify({ - text: i18n.t("Product type updated", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } else if ( updateData.productTypeUpdate.errors !== null && @@ -290,9 +286,10 @@ export const ProductTypeUpdate: React.FC = ({ ) } > - {i18n.t("Unassign", { - context: "unassign attribute from product type" - })} + ) }} @@ -315,9 +312,10 @@ export const ProductTypeUpdate: React.FC = ({ ) } > - {i18n.t("Unassign", { - context: "unassign attribute from product type" - })} + ) }} @@ -433,10 +431,7 @@ export const ProductTypeUpdate: React.FC = ({ onConfirm={handleProductTypeDelete} /> params.ids.length.toString(), - "..." - )} + attributeQuantity={maybe(() => params.ids.length)} confirmButtonState={unassignTransactionState} onClose={closeModal} onConfirm={handleBulkAttributeUnassign} diff --git a/src/products/components/ProductAttributes/ProductAttributes.tsx b/src/products/components/ProductAttributes/ProductAttributes.tsx index b6e96efc6..1da540333 100644 --- a/src/products/components/ProductAttributes/ProductAttributes.tsx +++ b/src/products/components/ProductAttributes/ProductAttributes.tsx @@ -7,6 +7,7 @@ import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; import makeStyles from "@material-ui/styles/makeStyles"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Grid from "@saleor/components/Grid"; @@ -18,7 +19,6 @@ import SingleAutocompleteSelectField, { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; -import i18n from "@saleor/i18n"; import { maybe } from "@saleor/misc"; import { ProductDetails_product_attributes_attribute_values } from "@saleor/products/types/ProductDetails"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; @@ -127,21 +127,30 @@ const ProductAttributes: React.FC = ({ onChange, onMultiChange }) => { + const intl = useIntl(); const classes = useStyles({}); const [expanded, setExpansionStatus] = React.useState(true); const toggleExpansion = () => setExpansionStatus(!expanded); return ( - +
- {i18n.t("{{ number }} Attributes", { - context: "number of attribute", - number: attributes.length - })} +
= ({ )} emptyOption name={`attribute:${attribute.label}`} - label={i18n.t("Value")} + label={intl.formatMessage({ + defaultMessage: "Value", + description: "attribute value" + })} value={attribute.value[0]} onChange={event => onChange(attribute.id, event.target.value) @@ -195,7 +207,10 @@ const ProductAttributes: React.FC = ({ diff --git a/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.tsx b/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.tsx index 0e109b9a6..ef069da4e 100644 --- a/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.tsx +++ b/src/products/components/ProductCategoryAndCollectionsForm/ProductCategoryAndCollectionsForm.tsx @@ -1,12 +1,12 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import React from "react"; +import { useIntl } from "react-intl"; import FormSpacer from "@saleor/components/FormSpacer"; import MultiSelectField from "@saleor/components/MultiSelectField"; import PageHeader from "@saleor/components/PageHeader"; import SingleSelectField from "@saleor/components/SingleSelectField"; -import i18n from "../../../i18n"; interface ProductCategoryAndCollectionsFormProps { categories?: Array<{ value: string; label: string }>; @@ -26,34 +26,47 @@ const ProductCategoryAndCollectionsForm = ({ category, loading, onChange -}: ProductCategoryAndCollectionsFormProps) => ( - - - - { + const intl = useIntl(); + + return ( + + - - - - -); + + + + + + + ); +}; ProductCategoryAndCollectionsForm.displayName = "ProductCategoryAndCollectionsForm"; export default ProductCategoryAndCollectionsForm; diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index cd9724688..08788dcfd 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -1,5 +1,6 @@ import { ContentState, convertToRaw, RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -16,6 +17,7 @@ import { SearchCategories_categories_edges_node } from "@saleor/containers/Searc import { SearchCollections_collections_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { sectionNames } from "@saleor/intl"; import { getChoices, ProductAttributeValueChoices, @@ -23,7 +25,6 @@ import { } from "@saleor/products/utils/data"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; -import i18n from "../../../i18n"; import { UserError } from "../../../types"; import { ProductCreateData_productTypes_edges_node_productAttributes } from "../../types/ProductCreateData"; import { @@ -96,6 +97,8 @@ export const ProductCreatePage: React.StatelessComponent< onBack, onSubmit }: ProductCreatePageProps) => { + const intl = useIntl(); + // Form values const { change: changeAttributeData, @@ -200,7 +203,9 @@ export const ProductCreatePage: React.StatelessComponent< return ( - {i18n.t("Products")} + + {intl.formatMessage(sectionNames.products)} +
@@ -239,9 +244,10 @@ export const ProductCreatePage: React.StatelessComponent< )} createStyles({ @@ -48,36 +49,45 @@ export const ProductDetailsForm = withStyles(styles, { errors, initialDescription, onChange - }: ProductDetailsFormProps) => ( - - - -
- { + const intl = useIntl(); + + return ( + + + +
+ +
+ + -
- - -
-
- ) + + + ); + } ); ProductDetailsForm.displayName = "ProductDetailsForm"; export default ProductDetailsForm; diff --git a/src/products/components/ProductImageNavigation/ProductImageNavigation.tsx b/src/products/components/ProductImageNavigation/ProductImageNavigation.tsx index 452e3bc7e..5873147ea 100644 --- a/src/products/components/ProductImageNavigation/ProductImageNavigation.tsx +++ b/src/products/components/ProductImageNavigation/ProductImageNavigation.tsx @@ -8,10 +8,10 @@ import { } from "@material-ui/core/styles"; import classNames from "classnames"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; const styles = (theme: Theme) => createStyles({ @@ -64,31 +64,41 @@ const ProductImageNavigation = withStyles(styles, { highlighted, images, onRowClick - }: ProductImageNavigationProps) => ( - - - - {images === undefined ? ( - - ) : ( -
- {images.map(image => ( -
- -
- ))} -
- )} -
-
- ) + }: ProductImageNavigationProps) => { + const intl = useIntl(); + + return ( + + + + {images === undefined ? ( + + ) : ( +
+ {images.map(image => ( +
+ +
+ ))} +
+ )} +
+
+ ); + } ); ProductImageNavigation.displayName = "ProductImageNavigation"; export default ProductImageNavigation; diff --git a/src/products/components/ProductImagePage/ProductImagePage.tsx b/src/products/components/ProductImagePage/ProductImagePage.tsx index f5b4ebe6e..5d14a47be 100644 --- a/src/products/components/ProductImagePage/ProductImagePage.tsx +++ b/src/products/components/ProductImagePage/ProductImagePage.tsx @@ -8,6 +8,7 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardTitle from "@saleor/components/CardTitle"; @@ -18,7 +19,7 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import ProductImageNavigation from "../ProductImageNavigation"; const styles = (theme: Theme) => @@ -69,68 +70,90 @@ const ProductImagePage = withStyles(styles, { name: "ProductImagePage" })( onDelete, onRowClick, onSubmit - }: ProductImagePageProps) => ( - - {({ change, data, hasChanged, submit }) => { - return ( - - {product} - - -
- - - - - { + const intl = useIntl(); + + return ( + + {({ change, data, hasChanged, submit }) => { + return ( + + {product} + + +
+ + + - - -
-
- - - - {!!image ? ( -
- -
- ) : ( - - )} -
-
-
-
- -
- ); - }} - - ) + + + +
+
+
+ + + + {!!image ? ( +
+ +
+ ) : ( + + )} +
+
+
+
+ +
+ ); + }} + + ); + } ); ProductImagePage.displayName = "ProductImagePage"; export default ProductImagePage; diff --git a/src/products/components/ProductImages/ProductImages.tsx b/src/products/components/ProductImages/ProductImages.tsx index 6fc860399..c5a389fe3 100644 --- a/src/products/components/ProductImages/ProductImages.tsx +++ b/src/products/components/ProductImages/ProductImages.tsx @@ -2,6 +2,7 @@ import Button from "@material-ui/core/Button"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import classNames from "classnames"; +import { useIntl } from "react-intl"; import { createStyles, @@ -12,10 +13,10 @@ import { import CardTitle from "@saleor/components/CardTitle"; import ImageTile from "@saleor/components/ImageTile"; import ImageUpload from "@saleor/components/ImageUpload"; +import { commonMessages } from "@saleor/intl"; import { ReorderAction } from "@saleor/types"; import React from "react"; import { SortableContainer, SortableElement } from "react-sortable-hoc"; -import i18n from "../../../i18n"; import { ProductDetails_product_images } from "../../types/ProductDetails"; const styles = (theme: Theme) => @@ -181,75 +182,83 @@ const ProductImages = withStyles(styles, { name: "ProductImages" })( onImageDelete, onImageReorder, onImageUpload - }: ProductImagesProps) => ( - - - - onImageUpload(event.target.files[0])} - type="file" - ref={ref => (this.upload = ref)} - /> - - } - /> -
- {images === undefined ? ( - -
-
- + }: ProductImagesProps) => { + const intl = useIntl(); + const upload = React.useRef(null); + + return ( + + + + onImageUpload(event.target.files[0])} + type="file" + ref={upload} + /> + + } + /> +
+ {images === undefined ? ( + +
+
+ +
-
- - ) : images.length > 0 ? ( - <> - - {({ isDragActive }) => ( - - - - )} - - - ) : ( - - )} -
- - ) + + ) : images.length > 0 ? ( + <> + + {({ isDragActive }) => ( + + + + )} + + + ) : ( + + )} +
+ + ); + } ); ProductImages.displayName = "ProductImages"; export default ProductImages; diff --git a/src/products/components/ProductListFilter/ProductListFilter.tsx b/src/products/components/ProductListFilter/ProductListFilter.tsx index 4381325cb..deeaca78b 100644 --- a/src/products/components/ProductListFilter/ProductListFilter.tsx +++ b/src/products/components/ProductListFilter/ProductListFilter.tsx @@ -1,8 +1,8 @@ import React from "react"; +import { useIntl } from "react-intl"; import { FieldType, IFilter } from "@saleor/components/Filter"; import FilterBar from "@saleor/components/FilterBar"; -import i18n from "@saleor/i18n"; import { FilterProps } from "@saleor/types"; import { StockAvailability } from "@saleor/types/globalTypes"; import { ProductListUrlFilters } from "../../urls"; @@ -17,79 +17,121 @@ export enum ProductFilterKeys { stock, query } -const filterMenu: IFilter = [ - { - children: [], - data: { - additionalText: i18n.t("is set as"), - fieldLabel: i18n.t("Status"), - options: [ - { - label: i18n.t("Visible"), - value: true - }, - { - label: i18n.t("Hidden"), - value: false - } - ], - type: FieldType.select - }, - label: i18n.t("Visibility"), - value: ProductFilterKeys.published.toString() - }, - { - children: [], - data: { - fieldLabel: i18n.t("Stock quantity"), - options: [ - { - label: i18n.t("Available"), - value: StockAvailability.IN_STOCK - }, - { - label: i18n.t("Out Of Stock"), - value: StockAvailability.OUT_OF_STOCK - } - ], - type: FieldType.select - }, - label: i18n.t("Stock"), - value: ProductFilterKeys.stock.toString() - }, - { - children: [ - { - children: [], - data: { - additionalText: i18n.t("equals"), - fieldLabel: null, - type: FieldType.price - }, - label: i18n.t("Specific Price"), - value: ProductFilterKeys.priceEqual.toString() - }, - { - children: [], - data: { - fieldLabel: i18n.t("Range"), - type: FieldType.rangePrice - }, - label: i18n.t("Range"), - value: ProductFilterKeys.priceRange.toString() - } - ], - data: { - fieldLabel: i18n.t("Price"), - type: FieldType.range - }, - label: i18n.t("Price"), - value: ProductFilterKeys.price.toString() - } -]; -const ProductListFilter: React.FC = props => ( - -); +const ProductListFilter: React.FC = props => { + const intl = useIntl(); + + const filterMenu: IFilter = [ + { + children: [], + data: { + additionalText: intl.formatMessage({ + defaultMessage: "is set as", + description: "product status is set as" + }), + fieldLabel: intl.formatMessage({ + defaultMessage: "Status", + description: "product status" + }), + options: [ + { + label: intl.formatMessage({ + defaultMessage: "Visible", + description: "product is visible" + }), + value: true + }, + { + label: intl.formatMessage({ + defaultMessage: "Hidden", + description: "product is hidden" + }), + value: false + } + ], + type: FieldType.select + }, + label: intl.formatMessage({ + defaultMessage: "Visibility", + description: "product visibility" + }), + value: ProductFilterKeys.published.toString() + }, + { + children: [], + data: { + fieldLabel: intl.formatMessage({ + defaultMessage: "Stock quantity" + }), + options: [ + { + label: intl.formatMessage({ + defaultMessage: "Available", + description: "product status" + }), + value: StockAvailability.IN_STOCK + }, + { + label: intl.formatMessage({ + defaultMessage: "Out Of Stock", + description: "product status" + }), + value: StockAvailability.OUT_OF_STOCK + } + ], + type: FieldType.select + }, + label: intl.formatMessage({ + defaultMessage: "Stock", + description: "product stock" + }), + value: ProductFilterKeys.stock.toString() + }, + { + children: [ + { + children: [], + data: { + additionalText: intl.formatMessage({ + defaultMessage: "equals", + description: "product price" + }), + fieldLabel: null, + type: FieldType.price + }, + label: intl.formatMessage({ + defaultMessage: "Specific Price" + }), + value: ProductFilterKeys.priceEqual.toString() + }, + { + children: [], + data: { + fieldLabel: intl.formatMessage({ + defaultMessage: "Range" + }), + type: FieldType.rangePrice + }, + label: intl.formatMessage({ + defaultMessage: "Range" + }), + value: ProductFilterKeys.priceRange.toString() + } + ], + data: { + fieldLabel: intl.formatMessage({ + defaultMessage: "Price" + }), + type: FieldType.range + }, + label: intl.formatMessage({ + defaultMessage: "Price" + }), + value: ProductFilterKeys.price.toString() + } + ]; + + return ; +}; ProductListFilter.displayName = "ProductListFilter"; export default ProductListFilter; diff --git a/src/products/components/ProductListPage/ProductListPage.tsx b/src/products/components/ProductListPage/ProductListPage.tsx index f94cf5ef0..6096fb686 100644 --- a/src/products/components/ProductListPage/ProductListPage.tsx +++ b/src/products/components/ProductListPage/ProductListPage.tsx @@ -4,6 +4,7 @@ import { Theme } from "@material-ui/core/styles"; import AddIcon from "@material-ui/icons/Add"; import makeStyles from "@material-ui/styles/makeStyles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import { CategoryDetails_category_products_edges_node } from "@saleor/categories/types/CategoryDetails"; import ColumnPicker, { @@ -14,7 +15,7 @@ import PageHeader from "@saleor/components/PageHeader"; import ProductList from "@saleor/components/ProductList"; import { ProductListColumns } from "@saleor/config"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { FilterPageProps, ListActions, PageListProps } from "@saleor/types"; import { toggle } from "@saleor/utils/lists"; import { ProductListUrlFilters } from "../../urls"; @@ -53,6 +54,7 @@ export const ProductListPage: React.FC = props => { onUpdateListSettings, ...listProps } = props; + const intl = useIntl(); const classes = useStyles(props); const [selectedColumns, setSelectedColumns] = useStateFromProps( settings.columns @@ -74,22 +76,31 @@ export const ProductListPage: React.FC = props => { const columns: ColumnPickerChoice[] = [ { - label: i18n.t("Published"), + label: intl.formatMessage({ + defaultMessage: "Published", + description: "product status" + }), value: "isPublished" as ProductListColumns }, { - label: i18n.t("Price"), + label: intl.formatMessage({ + defaultMessage: "Price", + description: "product price" + }), value: "price" as ProductListColumns }, { - label: i18n.t("Type"), + label: intl.formatMessage({ + defaultMessage: "Type", + description: "product type" + }), value: "productType" as ProductListColumns } ]; return ( - + = props => { variant="contained" data-tc="add-product" > - {i18n.t("Add product")} + + ( - - - - {canChangeType ? ( - - ) : ( - <> - - {i18n.t("Product Type")} - - {maybe(() => productType.name, "...")} - - - {i18n.t("Product Type")} - - - {maybe( - () => - productType.hasVariants - ? i18n.t("Configurable") - : i18n.t("Simple"), - "..." - )} - - - )} - -
- - { + const intl = useIntl(); + + return ( + + - -
- - + {canChangeType ? ( + + ) : ( + <> + + + + {maybe(() => productType.name, "...")} + + + + + + {maybe( + () => + productType.hasVariants + ? intl.formatMessage({ + defaultMessage: "Configurable", + description: "product is configurable" + }) + : intl.formatMessage({ + defaultMessage: "Simple", + description: "product is not configurable" + }), + "..." + )} + + )} - onChange={onCollectionChange} - fetchChoices={fetchCollections} - data-tc="collections" - /> -
-
- ) + +
+ + + +
+ + +
+ + ); + } ); ProductOrganization.displayName = "ProductOrganization"; export default ProductOrganization; diff --git a/src/products/components/ProductPricing/ProductPricing.tsx b/src/products/components/ProductPricing/ProductPricing.tsx index fc22a32f0..fc74d5d38 100644 --- a/src/products/components/ProductPricing/ProductPricing.tsx +++ b/src/products/components/ProductPricing/ProductPricing.tsx @@ -7,11 +7,11 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import PriceField from "@saleor/components/PriceField"; -import i18n from "../../../i18n"; const styles = (theme: Theme) => createStyles({ @@ -33,31 +33,45 @@ interface ProductPricingProps extends WithStyles { } const ProductPricing = withStyles(styles, { name: "ProductPricing" })( - ({ classes, currency, data, disabled, onChange }: ProductPricingProps) => ( - - - - - -
- { + const intl = useIntl(); + + return ( + + + -
-
-
- ) + + +
+ +
+
+ + ); + } ); ProductPricing.displayName = "ProductPricing"; export default ProductPricing; diff --git a/src/products/components/ProductStock/ProductStock.tsx b/src/products/components/ProductStock/ProductStock.tsx index 3407fcb84..f60d5f2fa 100644 --- a/src/products/components/ProductStock/ProductStock.tsx +++ b/src/products/components/ProductStock/ProductStock.tsx @@ -8,9 +8,9 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { ProductDetails_product } from "../../types/ProductDetails"; @@ -35,39 +35,70 @@ interface ProductStockProps extends WithStyles { } const ProductStock = withStyles(styles, { name: "ProductStock" })( - ({ classes, data, disabled, product, onChange, errors }: ProductStockProps) => ( - - - -
- - product.variants[0].quantityAllocated) - }) - : undefined - } - /> -
-
-
- ) + ({ + classes, + data, + disabled, + product, + onChange, + errors + }: ProductStockProps) => { + const intl = useIntl(); + + return ( + + + +
+ + product.variants[0].quantityAllocated + ) + } + ) + : undefined + } + /> +
+
+
+ ); + } ); ProductStock.displayName = "ProductStock"; export default ProductStock; diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 169aa649e..acd0f4c70 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -1,5 +1,6 @@ import { convertFromRaw, RawDraftContentState } from "draft-js"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -15,7 +16,7 @@ import { SearchCategories_categories_edges_node } from "@saleor/containers/Searc import { SearchCollections_collections_edges_node } from "@saleor/containers/SearchCollections/types/SearchCollections"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { ListActions, UserError } from "@saleor/types"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; @@ -107,6 +108,7 @@ export const ProductUpdatePage: React.FC = ({ toggleAll, toolbar }) => { + const intl = useIntl(); const attributeInput = React.useMemo( () => getAttributeInputFromProduct(product), [product] @@ -188,7 +190,9 @@ export const ProductUpdatePage: React.FC = ({ return ( <> - {i18n.t("Products")} + + {intl.formatMessage(sectionNames.products)} +
@@ -259,6 +263,10 @@ export const ProductUpdatePage: React.FC = ({ loading={disabled} onClick={onSeoClick} onChange={change} + helperText={intl.formatMessage({ + defaultMessage: + "Add search engine title and description to make this product easier to find" + })} />
diff --git a/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx b/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx index a8da22fe2..b14ae526e 100644 --- a/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx +++ b/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx @@ -1,6 +1,7 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Grid from "@saleor/components/Grid"; @@ -9,7 +10,7 @@ import SingleAutocompleteSelectField, { } from "@saleor/components/SingleAutocompleteSelectField"; import Skeleton from "@saleor/components/Skeleton"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { ProductVariant_attributes_attribute_values } from "../../types/ProductVariant"; export interface VariantAttributeInputData { @@ -67,40 +68,46 @@ const ProductVariantAttributes: React.FC = ({ disabled, errors, onChange -}) => ( - - - - - {attributes === undefined ? ( - - ) : ( - attributes.map((attribute, attributeIndex) => { - return ( - onChange(attribute.id, event.target.value)} - value={getAttributeValue(attribute.id, attributes)} - choices={getAttributeValueChoices(attribute.id, attributes)} - allowCustomValues - data-tc="variant-attribute-input" - /> - ); - }) - )} - - - -); +}) => { + const intl = useIntl(); + + return ( + + + + + {attributes === undefined ? ( + + ) : ( + attributes.map((attribute, attributeIndex) => { + return ( + onChange(attribute.id, event.target.value)} + value={getAttributeValue(attribute.id, attributes)} + choices={getAttributeValueChoices(attribute.id, attributes)} + allowCustomValues + data-tc="variant-attribute-input" + /> + ); + }) + )} + + + + ); +}; ProductVariantAttributes.displayName = "ProductVariantAttributes"; export default ProductVariantAttributes; diff --git a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx index 1c70303b2..73c2a4c35 100644 --- a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx +++ b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -16,7 +17,6 @@ import { getVariantAttributeErrors, getVariantAttributeInputFromProduct } from "@saleor/products/utils/data"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { UserError } from "../../../types"; import { ProductVariantCreateData_product } from "../../types/ProductVariantCreateData"; @@ -63,6 +63,7 @@ const ProductVariantCreatePage: React.FC = ({ onSubmit, onVariantClick }) => { + const intl = useIntl(); const attributeInput = React.useMemo( () => getVariantAttributeInputFromProduct(product), [product] @@ -150,8 +151,14 @@ const ProductVariantCreatePage: React.FC = ({ createStyles({ @@ -50,21 +51,25 @@ const ProductVariantDeleteDialog = withStyles(styles, { }: ProductVariantDeleteDialogProps) => ( - {i18n.t("Delete variant", { context: "title" })} + - {{name}}?", - { name } - ) - }} - /> + + + - {i18n.t("Delete variant", { context: "button" })} + diff --git a/src/products/components/ProductVariantImageSelectDialog/ProductVariantImageSelectDialog.tsx b/src/products/components/ProductVariantImageSelectDialog/ProductVariantImageSelectDialog.tsx index 028a5eacd..bd7e1717d 100644 --- a/src/products/components/ProductVariantImageSelectDialog/ProductVariantImageSelectDialog.tsx +++ b/src/products/components/ProductVariantImageSelectDialog/ProductVariantImageSelectDialog.tsx @@ -11,8 +11,9 @@ import { } from "@material-ui/core/styles"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage } from "react-intl"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { ProductImage } from "../../types/ProductImage"; const styles = (theme: Theme) => @@ -72,7 +73,10 @@ const ProductVariantImageSelectDialog = withStyles(styles, { }: ProductVariantImageSelectDialogProps) => ( - {i18n.t("Image selection", { context: "title" })} +
@@ -97,7 +101,7 @@ const ProductVariantImageSelectDialog = withStyles(styles, {
diff --git a/src/products/components/ProductVariantImages/ProductVariantImages.tsx b/src/products/components/ProductVariantImages/ProductVariantImages.tsx index 6dda4936c..7d492930f 100644 --- a/src/products/components/ProductVariantImages/ProductVariantImages.tsx +++ b/src/products/components/ProductVariantImages/ProductVariantImages.tsx @@ -9,10 +9,10 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { ProductImage } from "../../types/ProductImage"; const styles = (theme: Theme) => @@ -54,41 +54,51 @@ interface ProductVariantImagesProps extends WithStyles { export const ProductVariantImages = withStyles(styles, { name: "ProductVariantImages" -})(({ classes, disabled, images, onImageAdd }: ProductVariantImagesProps) => ( - - - {i18n.t("Choose photos")} - - } - /> - -
- {images === undefined || images === null ? ( - - ) : images.length > 0 ? ( - images - .sort((prev, next) => (prev.sortOrder > next.sortOrder ? 1 : -1)) - .map(tile => ( -
- -
- )) - ) : ( - - {i18n.t("Select a specific variant image from product images")} - - )} -
-
-
-)); +})(({ classes, disabled, images, onImageAdd }: ProductVariantImagesProps) => { + const intl = useIntl(); + + return ( + + + + + } + /> + +
+ {images === undefined || images === null ? ( + + ) : images.length > 0 ? ( + images + .sort((prev, next) => (prev.sortOrder > next.sortOrder ? 1 : -1)) + .map(tile => ( +
+ +
+ )) + ) : ( + + + + )} +
+
+
+ ); +}); ProductVariantImages.displayName = "ProductVariantImages"; export default ProductVariantImages; diff --git a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx index 96f534a15..7d198b50d 100644 --- a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx +++ b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx @@ -12,11 +12,11 @@ import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ProductVariantCreateData_product_variants } from "../../types/ProductVariantCreateData"; import { ProductVariantDetails_productVariant } from "../../types/ProductVariantDetails"; @@ -63,52 +63,70 @@ const ProductVariantNavigation = withStyles(styles, { variants, onAdd, onRowClick - }: ProductVariantNavigationProps) => ( - - - - - {renderCollection(variants, variant => ( - onRowClick(variant.id) : undefined} - > - variant.images[0].url, - fallbackThumbnail - )} - /> - - {variant ? variant.name || variant.sku : } - - - ))} - {onAdd ? ( - - - - - - ) : ( - - - - {i18n.t("New Variant")} - - - )} - -
-
- ) + }: ProductVariantNavigationProps) => { + const intl = useIntl(); + + return ( + + + + + {renderCollection(variants, variant => ( + onRowClick(variant.id) : undefined} + > + variant.images[0].url, + fallbackThumbnail + )} + /> + + {variant ? variant.name || variant.sku : } + + + ))} + {onAdd ? ( + + + + + + ) : ( + + + + + + + )} + +
+
+ ); + } ); ProductVariantNavigation.displayName = "ProductVariantNavigation"; export default ProductVariantNavigation; diff --git a/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx b/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx index 077a4b49d..8cfd5bc12 100644 --- a/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx +++ b/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx @@ -7,10 +7,10 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import PriceField from "@saleor/components/PriceField"; -import i18n from "../../../i18n"; const styles = (theme: Theme) => createStyles({ @@ -39,43 +39,68 @@ const ProductVariantPrice = withStyles(styles, { name: "ProductVariantPrice" })( priceOverride, loading, onChange - }: ProductVariantPriceProps) => ( - - - -
-
- + }: ProductVariantPriceProps) => { + const intl = useIntl(); + + return ( + + + +
+
+ +
+
+ +
-
- -
-
- - - ) + + + ); + } ); ProductVariantPrice.displayName = "ProductVariantPrice"; export default ProductVariantPrice; diff --git a/src/products/components/ProductVariantStock/ProductVariantStock.tsx b/src/products/components/ProductVariantStock/ProductVariantStock.tsx index 748f85362..295d0962b 100644 --- a/src/products/components/ProductVariantStock/ProductVariantStock.tsx +++ b/src/products/components/ProductVariantStock/ProductVariantStock.tsx @@ -8,9 +8,9 @@ import { } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import i18n from "../../../i18n"; const styles = (theme: Theme) => createStyles({ @@ -42,48 +42,67 @@ const ProductVariantStock = withStyles(styles, { name: "ProductVariantStock" })( stockAllocated, loading, onChange - }: ProductVariantStockProps) => ( - - - -
-
- + }: ProductVariantStockProps) => { + const intl = useIntl(); + + return ( + + + +
+
+ +
+
+ +
-
- -
-
- - - ) + + + ); + } ); ProductVariantStock.displayName = "ProductVariantStock"; export default ProductVariantStock; diff --git a/src/products/components/ProductVariants/ProductVariants.tsx b/src/products/components/ProductVariants/ProductVariants.tsx index 9b88a7e3f..c7467c99a 100644 --- a/src/products/components/ProductVariants/ProductVariants.tsx +++ b/src/products/components/ProductVariants/ProductVariants.tsx @@ -14,6 +14,7 @@ import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Checkbox from "@saleor/components/Checkbox"; @@ -21,7 +22,6 @@ import Money from "@saleor/components/Money"; import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; import TableHead from "@saleor/components/TableHead"; -import i18n from "../../../i18n"; import { renderCollection } from "../../../misc"; import { ListActions } from "../../../types"; import { ProductDetails_product_variants } from "../../types/ProductDetails"; @@ -88,130 +88,162 @@ export const ProductVariants = withStyles(styles, { name: "ProductVariants" })( toggle, toggleAll, toolbar - }: ProductVariantsProps) => ( - - - - - - } - /> - - - {i18n.t( - "Use variants for products that come in a variety of versions for example different sizes or colors" - )} - - - - - {i18n.t("Name")} - - {i18n.t("Status")} - - {i18n.t("SKU")} - - - {i18n.t("Price")} - - - - - {renderCollection( - variants, - variant => { - const isSelected = variant ? isChecked(variant.id) : false; + }: ProductVariantsProps) => { + const intl = useIntl(); - return ( - - - toggle(variant.id)} - /> - - - {variant ? variant.name || variant.sku : } - - - {variant ? ( - 0 ? "success" : "error"} - label={ - variant.stockQuantity > 0 - ? i18n.t("Available") - : i18n.t("Unavailable") - } + return ( + + + + + + } + /> + + + + + +
+ + + + + + + + + + + + + + + + + + {renderCollection( + variants, + variant => { + const isSelected = variant ? isChecked(variant.id) : false; + + return ( + + + toggle(variant.id)} /> - ) : ( - - )} - - - {variant ? variant.sku : } - - - + + + {variant ? variant.name || variant.sku : } + + {variant ? ( - variant.priceOverride ? ( - - ) : fallbackPrice ? ( - - ) : ( - - ) + 0 ? "success" : "error" + } + label={ + variant.stockQuantity > 0 + ? intl.formatMessage({ + defaultMessage: "Available", + description: "product variant status" + }) + : intl.formatMessage({ + defaultMessage: "Unavailable", + description: "product variant status" + }) + } + /> ) : ( )} - + + {variant ? variant.sku : } + + + + {variant ? ( + variant.priceOverride ? ( + + ) : fallbackPrice ? ( + + ) : ( + + ) + ) : ( + + )} + + + + ); + }, + () => ( + + + + - ); - }, - () => ( - - - {i18n.t("This product has no variants")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); ProductVariants.displayName = "ProductVariants"; export default ProductVariants; diff --git a/src/products/index.tsx b/src/products/index.tsx index c82475310..0a8a1e767 100644 --- a/src/products/index.tsx +++ b/src/products/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { productAddPath, productImagePath, @@ -86,28 +87,32 @@ const ProductVariantCreate: React.StatelessComponent< ); }; -const Component = () => ( - <> - - - - - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + + + + ); +}; export default Component; diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 47b70babe..e3528a3b3 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; @@ -7,7 +8,6 @@ import useShop from "@saleor/hooks/useShop"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../config"; import SearchCategories from "../../containers/SearchCategories"; import SearchCollections from "../../containers/SearchCollections"; -import i18n from "../../i18n"; import { decimal, getMutationState, maybe } from "../../misc"; import ProductCreatePage, { ProductCreatePageSubmitData @@ -27,6 +27,7 @@ export const ProductUpdate: React.StatelessComponent< const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const handleAttributesEdit = undefined; const handleBack = () => navigate(productListUrl()); @@ -41,7 +42,9 @@ export const ProductUpdate: React.StatelessComponent< const handleSuccess = (data: ProductCreate) => { if (data.productCreate.errors.length === 0) { notify({ - text: i18n.t("Product created") + text: intl.formatMessage({ + defaultMessage: "Product created" + }) }); navigate(productUrl(data.productCreate.product.id)); } else { @@ -109,7 +112,12 @@ export const ProductUpdate: React.StatelessComponent< ); return ( <> - + shop.defaultCurrency)} categories={maybe( @@ -127,7 +135,10 @@ export const ProductUpdate: React.StatelessComponent< )} fetchCategories={searchCategory} fetchCollections={searchCollection} - header={i18n.t("New Product")} + header={intl.formatMessage({ + defaultMessage: "New Product", + description: "page header" + })} productTypes={maybe(() => data.productTypes.edges.map(edge => edge.node) )} diff --git a/src/products/views/ProductImage.tsx b/src/products/views/ProductImage.tsx index bb7e4a193..765e7bc4b 100644 --- a/src/products/views/ProductImage.tsx +++ b/src/products/views/ProductImage.tsx @@ -1,10 +1,10 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; import { getMutationState, maybe } from "../../misc"; import ProductImagePage from "../components/ProductImagePage"; import { @@ -32,6 +32,7 @@ export const ProductImage: React.StatelessComponent = ({ }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleBack = () => navigate(productUrl(productId)); const handleUpdateSuccess = (data: ProductImageUpdate) => { @@ -103,19 +104,15 @@ export const ProductImage: React.StatelessComponent = ({ } onConfirm={handleDelete} open={params.action === "remove"} - title={i18n.t("Remove image", { - context: "modal title" + title={intl.formatMessage({ + defaultMessage: "Remove Image", + description: "dialog header" })} variant="delete" confirmButtonState={deleteTransitionState} > - {i18n.t( - "Are you sure you want to remove this image?", - { - context: "modal content" - } - )} + diff --git a/src/products/views/ProductList/ProductList.tsx b/src/products/views/ProductList/ProductList.tsx index 17f6d7e00..39db0c7e6 100644 --- a/src/products/views/ProductList/ProductList.tsx +++ b/src/products/views/ProductList/ProductList.tsx @@ -3,6 +3,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; @@ -19,7 +20,6 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; -import i18n from "@saleor/i18n"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import ProductListPage from "../../components/ProductListPage"; @@ -67,6 +67,8 @@ export const ProductList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.PRODUCT_LIST ); + const intl = useIntl(); + const tabs = getFilterTabs(); const currentTab = @@ -155,7 +157,9 @@ export const ProductList: React.StatelessComponent = ({ if (data.productBulkDelete.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Products removed") + text: intl.formatMessage({ + defaultMessage: "Products removed" + }) }); reset(); refetch(); @@ -166,7 +170,10 @@ export const ProductList: React.StatelessComponent = ({ if (data.productBulkPublish.errors.length === 0) { closeModal(); notify({ - text: i18n.t("Changed publication status") + text: intl.formatMessage({ + defaultMessage: "Changed publication status", + description: "product status update notification" + }) }); reset(); refetch(); @@ -210,7 +217,8 @@ export const ProductList: React.StatelessComponent = ({ currencySymbol, locale }, - changeFilterField + changeFilterField, + intl )} onAdd={() => navigate(productAddUrl)} disabled={loading} @@ -235,13 +243,19 @@ export const ProductList: React.StatelessComponent = ({ openModal("unpublish", listElements) } > - {i18n.t("Unpublish")} + = ({ variables: { ids: params.ids } }) } - title={i18n.t("Remove products")} + title={intl.formatMessage({ + defaultMessage: "Delete Products", + description: "dialog header" + })} variant="delete" > - {{ number }} products?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + = ({ } }) } - title={i18n.t("Publish products")} + title={intl.formatMessage({ + defaultMessage: "Publish Products", + description: "dialog header" + })} > - {{ number }} products?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + = ({ } }) } - title={i18n.t("Unpublish products")} + title={intl.formatMessage({ + defaultMessage: "Unpublish Products", + description: "dialog header" + })} > - {{ number }} products?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + void + onFilterDelete: (filters: ProductListUrlFilters) => void, + intl: IntlShape ): Filter[] { let filterChips: Filter[] = []; @@ -77,7 +109,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: i18n.t("Price is {{ price }}", { + label: intl.formatMessage(filterMessages.priceIs, { price: parseFloat(filters.priceFrom).toLocaleString( formatData.locale, { @@ -99,7 +131,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: i18n.t("Price from {{ price }}", { + label: intl.formatMessage(filterMessages.priceFrom, { price: parseFloat(filters.priceFrom).toLocaleString( formatData.locale, { @@ -121,7 +153,7 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: i18n.t("Price to {{ price }}", { + label: intl.formatMessage(filterMessages.priceTo, { price: parseFloat(filters.priceTo).toLocaleString( formatData.locale, { @@ -147,8 +179,8 @@ export function createFilterChips( { label: filters.status === StockAvailability.IN_STOCK.toString() - ? i18n.t("Available") - : i18n.t("Out Of Stock"), + ? intl.formatMessage(filterMessages.available) + : intl.formatMessage(filterMessages.outOfStock), onClick: () => onFilterDelete({ ...filters, @@ -162,10 +194,9 @@ export function createFilterChips( filterChips = [ ...filterChips, { - label: - filters.isPublished === StockAvailability.IN_STOCK.toString() - ? i18n.t("Published") - : i18n.t("Hidden"), + label: !!filters.isPublished + ? intl.formatMessage(filterMessages.published) + : intl.formatMessage(filterMessages.hidden), onClick: () => onFilterDelete({ ...filters, diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 626d60907..9e9e9f866 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import placeholderImg from "@assets/images/placeholder255x255.png"; import ActionDialog from "@saleor/components/ActionDialog"; @@ -9,10 +10,10 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; +import { commonMessages } from "@saleor/intl"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; import SearchCategories from "../../../containers/SearchCategories"; import SearchCollections from "../../../containers/SearchCollections"; -import i18n from "../../../i18n"; import { getMutationState, maybe } from "../../../misc"; import { productTypeUrl } from "../../../productTypes/urls"; import ProductUpdatePage from "../../components/ProductUpdatePage"; @@ -53,6 +54,7 @@ export const ProductUpdate: React.StatelessComponent = ({ const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); + const intl = useIntl(); const openModal = (action: ProductUrlDialog) => navigate( @@ -73,12 +75,18 @@ export const ProductUpdate: React.StatelessComponent = ({ > {({ data, loading, refetch }) => { const handleDelete = () => { - notify({ text: i18n.t("Product removed") }); + notify({ + text: intl.formatMessage({ + defaultMessage: "Product removed" + }) + }); navigate(productListUrl()); }; const handleUpdate = (data: ProductUpdateMutationResult) => { if (data.productUpdate.errors.length === 0) { - notify({ text: i18n.t("Saved changes") }); + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); } else { const attributeError = data.productUpdate.errors.find( err => err.field === "attributes" @@ -103,7 +111,7 @@ export const ProductUpdate: React.StatelessComponent = ({ }; const handleImageDeleteSuccess = () => notify({ - text: i18n.t("Image successfully deleted") + text: intl.formatMessage(commonMessages.savedChanges) }); const handleVariantAdd = () => navigate(productVariantAddUrl(id)); @@ -276,18 +284,20 @@ export const ProductUpdate: React.StatelessComponent = ({ confirmButtonState={deleteTransitionState} onConfirm={() => deleteProduct.mutate({ id })} variant="delete" - title={i18n.t("Remove product")} + title={intl.formatMessage({ + defaultMessage: "Delete Product", + description: "dialog header" + })} > - {{ name }}?", - { - name: product ? product.name : undefined - } - ) - }} - /> + + + = ({ }) } variant="delete" - title={i18n.t("Remove product variants")} + title={intl.formatMessage({ + defaultMessage: "Delete Product Variants", + description: "dialog header" + })} > - {{ number }} variants?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + ); diff --git a/src/products/views/ProductVariant.tsx b/src/products/views/ProductVariant.tsx index 88adf4d4d..4d3e1e716 100644 --- a/src/products/views/ProductVariant.tsx +++ b/src/products/views/ProductVariant.tsx @@ -1,10 +1,11 @@ import React from "react"; +import { useIntl } from "react-intl"; import placeholderImg from "@assets/images/placeholder255x255.png"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { decimal, getMutationState, maybe } from "../../misc"; import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog"; import ProductVariantPage, { @@ -33,6 +34,7 @@ export const ProductVariant: React.StatelessComponent = ({ }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); return ( = ({ const variant = data ? data.productVariant : undefined; const handleBack = () => navigate(productUrl(productId)); const handleDelete = () => { - notify({ text: i18n.t("Variant removed") }); + notify({ + text: intl.formatMessage({ + defaultMessage: "Variant removed" + }) + }); navigate(productUrl(productId)); }; const handleUpdate = (data: VariantUpdate) => { if (!maybe(() => data.productVariantUpdate.errors.length)) { - notify({ text: i18n.t("Changes saved") }); + notify({ text: intl.formatMessage(commonMessages.savedChanges) }); } }; diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index ede273a8e..2735880dc 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -1,10 +1,10 @@ import React from "react"; +import { useIntl } from "react-intl"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; import { decimal, getMutationState, maybe } from "../../misc"; import ProductVariantCreatePage, { ProductVariantCreatePageSubmitData @@ -24,6 +24,7 @@ export const ProductVariant: React.StatelessComponent = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); return ( = ({ {({ data, loading: productLoading }) => { const handleCreateSuccess = (data: VariantCreate) => { if (data.productVariantCreate.errors.length === 0) { - notify({ text: i18n.t("Product created") }); + notify({ + text: intl.formatMessage({ + defaultMessage: "Product created" + }) + }); navigate( productVariantEditUrl( productId, @@ -81,7 +86,12 @@ export const ProductVariant: React.StatelessComponent = ({ ); return ( <> - + shop.defaultCurrency)} errors={maybe( @@ -89,7 +99,10 @@ export const ProductVariant: React.StatelessComponent = ({ variantCreateResult.data.productVariantCreate.errors, [] )} - header={i18n.t("Add Variant")} + header={intl.formatMessage({ + defaultMessage: "Add Variant", + description: "header" + })} loading={disableForm} product={maybe(() => data.product)} onBack={handleBack} diff --git a/src/queries.tsx b/src/queries.tsx index 58266d99e..bde4cdb04 100644 --- a/src/queries.tsx +++ b/src/queries.tsx @@ -3,12 +3,12 @@ import { DocumentNode } from "graphql"; import gql from "graphql-tag"; import React from "react"; import { Query, QueryResult } from "react-apollo"; +import { useIntl } from "react-intl"; import AppProgress from "./components/AppProgress"; import ErrorPage from "./components/ErrorPage/ErrorPage"; import useNavigator from "./hooks/useNavigator"; import useNotifier from "./hooks/useNotifier"; -import i18n from "./i18n"; import { RequireAtLeastOne } from "./misc"; export interface LoadMore { @@ -69,6 +69,7 @@ export function TypedQuery( return ({ children, displayLoader, skip, variables, require }) => { const navigate = useNavigator(); const pushMessage = useNotifier(); + const intl = useIntl(); return ( @@ -82,9 +83,15 @@ export function TypedQuery( > {queryData => { if (queryData.error) { - const msg = i18n.t("Something went wrong: {{ message }}", { - message: queryData.error.message - }); + const msg = intl.formatMessage( + { + defaultMessage: "Something went wrong. {errorMessage}", + description: "error message" + }, + { + message: queryData.error.message + } + ); pushMessage({ text: msg }); } diff --git a/src/shipping/components/ShippingWeightUnitForm/ShippingWeightUnitForm.tsx b/src/shipping/components/ShippingWeightUnitForm/ShippingWeightUnitForm.tsx index ef3f1065e..86a7b50b9 100644 --- a/src/shipping/components/ShippingWeightUnitForm/ShippingWeightUnitForm.tsx +++ b/src/shipping/components/ShippingWeightUnitForm/ShippingWeightUnitForm.tsx @@ -3,12 +3,13 @@ import Card from "@material-ui/core/Card"; import CardActions from "@material-ui/core/CardActions"; import CardContent from "@material-ui/core/CardContent"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Form from "@saleor/components/Form"; import Hr from "@saleor/components/Hr"; import SingleSelectField from "@saleor/components/SingleSelectField"; -import i18n from "../../../i18n"; +import { buttonMessages, sectionNames } from "@saleor/intl"; import { WeightUnitsEnum } from "../../../types/globalTypes"; export interface FormData { @@ -24,6 +25,7 @@ export interface ShippingWeightUnitFormProps { const ShippingWeightUnitForm: React.StatelessComponent< ShippingWeightUnitFormProps > = ({ defaultWeightUnit, disabled, onSubmit }) => { + const intl = useIntl(); const initialForm: FormData = { unit: defaultWeightUnit }; @@ -31,11 +33,7 @@ const ShippingWeightUnitForm: React.StatelessComponent<
onSubmit(formData.unit)}> {({ change, data, submit }) => ( - + diff --git a/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.tsx b/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.tsx index 9f59522bd..0cc4bc372 100644 --- a/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.tsx +++ b/src/shipping/components/ShippingZoneCountriesAssignDialog/ShippingZoneCountriesAssignDialog.tsx @@ -17,6 +17,7 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import { filter } from "fuzzaldrin"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import ConfirmButton, { @@ -27,7 +28,7 @@ import FormSpacer from "@saleor/components/FormSpacer"; import Hr from "@saleor/components/Hr"; // tslint:disable no-submodule-imports import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; interface FormData { countries: string[]; @@ -77,6 +78,8 @@ const ShippingZoneCountriesAssignDialog = withStyles(styles, { initial, onConfirm }: ShippingZoneCountriesAssignDialogProps & WithStyles) => { + const intl = useIntl(); + const initialForm: FormData = { countries: initial, query: "", @@ -95,23 +98,26 @@ const ShippingZoneCountriesAssignDialog = withStyles(styles, { return ( <> - {i18n.t("Assign Countries")} + + + - {i18n.t( - "Choose countries you want to add to shipping zone from list below" - )} + change(event, () => fetch(data.query))} - label={i18n.t("Search Countries", { - context: "country search input label" + label={intl.formatMessage({ + defaultMessage: "Search Countries" })} - placeholder={i18n.t("Search by country name", { - context: "country search input placeholder" + placeholder={intl.formatMessage({ + defaultMessage: "Search by country name" })} fullWidth /> @@ -120,17 +126,15 @@ const ShippingZoneCountriesAssignDialog = withStyles(styles, { - {i18n.t("Quick Pick")} + - {i18n.t("Rest of the World")} + - {i18n.t( - "If selected, this will add all of the countries not selected to other shipping zones" - )} + - {i18n.t("Countries A to Z", { - context: "country selection" - })} +
@@ -209,7 +214,7 @@ const ShippingZoneCountriesAssignDialog = withStyles(styles, { - {i18n.t("Assign countries", { context: "button" })} + diff --git a/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx b/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx index 63f27bf09..531e6c863 100644 --- a/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx +++ b/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -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 "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { CountryFragment } from "../../../taxes/types/CountryFragment"; import { UserError } from "../../../types"; import ShippingZoneCountriesAssignDialog from "../ShippingZoneCountriesAssignDialog"; @@ -33,6 +34,7 @@ export interface ShippingZoneCreatePageProps { const ShippingZoneCreatePage: React.StatelessComponent< ShippingZoneCreatePageProps > = ({ countries, disabled, errors, onBack, onSubmit, saveButtonBarState }) => { + const intl = useIntl(); const [isModalOpened, setModalStatus] = React.useState(false); const toggleModal = () => setModalStatus(!isModalOpened); @@ -47,8 +49,15 @@ const ShippingZoneCreatePage: React.StatelessComponent< {({ change, data, errors: formErrors, hasChanged, submit }) => ( <> - {i18n.t("Shipping")} - + + {intl.formatMessage(sectionNames.shipping)} + +
@@ -82,7 +93,9 @@ const ShippingZoneCreatePage: React.StatelessComponent< } } as any) } - title={i18n.t("Countries")} + title={intl.formatMessage({ + defaultMessage: "Countries" + })} />
diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index a6d573f68..a4324affb 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -9,7 +10,6 @@ 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 "../../../i18n"; import { maybe } from "../../../misc"; import { UserError } from "../../../types"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; @@ -56,6 +56,8 @@ const ShippingZoneDetailsPage: React.StatelessComponent< saveButtonBarState, shippingZone }) => { + const intl = useIntl(); + const initialForm: FormData = { name: maybe(() => shippingZone.name, "") }; @@ -63,7 +65,9 @@ const ShippingZoneDetailsPage: React.StatelessComponent< {({ change, data, errors: formErrors, hasChanged, submit }) => ( - {i18n.t("Shipping")} + + + shippingZone.name)} />
@@ -79,17 +83,21 @@ const ShippingZoneDetailsPage: React.StatelessComponent< emptyText={maybe( () => shippingZone.default - ? i18n.t( - "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" - ) - : i18n.t( - "Currently, there are no countries assigned to this shipping zone" - ), + ? intl.formatMessage({ + defaultMessage: + "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" + }) + : intl.formatMessage({ + defaultMessage: + "Currently, there are no countries assigned to this shipping zone" + }), "..." )} onCountryAssign={onCountryAdd} onCountryUnassign={onCountryRemove} - title={i18n.t("Countries")} + title={intl.formatMessage({ + defaultMessage: "Countries" + })} /> = ({ data, errors, onChange -}) => ( - - - - { + const intl = useIntl(); + + return ( + + - - -); + + + + + ); +}; ShippingZoneInfo.displayName = "ShippingZoneInfo"; export default ShippingZoneInfo; diff --git a/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.tsx b/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.tsx index e08f6e5dd..baf025bce 100644 --- a/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.tsx +++ b/src/shipping/components/ShippingZoneRateDialog/ShippingZoneRateDialog.tsx @@ -12,6 +12,7 @@ import { 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 ConfirmButton, { ConfirmButtonTransitionState @@ -21,7 +22,7 @@ import Form from "@saleor/components/Form"; import FormSpacer from "@saleor/components/FormSpacer"; import Hr from "@saleor/components/Hr"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; import { maybe } from "../../../misc"; import { FormErrors, UserError } from "../../../types"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; @@ -77,6 +78,8 @@ const ShippingZoneRateDialog = withStyles(styles, { rate, variant }: ShippingZoneRateDialogProps & WithStyles) => { + const intl = useIntl(); + const initialForm: FormData = action === "create" ? { @@ -122,11 +125,25 @@ const ShippingZoneRateDialog = withStyles(styles, { {variant === ShippingMethodTypeEnum.PRICE ? action === "create" - ? i18n.t("Add Price Rate") - : i18n.t("Edit Price Rate") + ? intl.formatMessage({ + defaultMessage: "Add Price Rate", + description: "dialog header" + }) + : intl.formatMessage({ + defaultMessage: "Edit Price Rate", + description: "dialog header" + }) : action === "create" - ? i18n.t("Add Weight Rate") - : i18n.t("Edit Weight Rate")} + ? intl.formatMessage({ + defaultMessage: "Add Weight Rate", + description: + "add weight based shipping method, dialog header" + }) + : intl.formatMessage({ + defaultMessage: "Edit Weight Rate", + description: + "edit weight based shipping method, dialog header" + })} {variant === ShippingMethodTypeEnum.PRICE - ? i18n.t("Value range") - : i18n.t("Weight range")} + ? intl.formatMessage({ + defaultMessage: "Value range", + description: "order price range" + }) + : intl.formatMessage({ + defaultMessage: "Weight range", + description: "order weight range" + })} - {i18n.t("There are no value limits")} + {variant === ShippingMethodTypeEnum.PRICE - ? i18n.t( - "This rate will apply to all orders of all prices" - ) - : i18n.t( - "This rate will apply to all orders of all weights" - )} + ? intl.formatMessage({ + defaultMessage: + "This rate will apply to all orders of all prices" + }) + : intl.formatMessage({ + defaultMessage: + "This rate will apply to all orders of all weights" + })} } @@ -194,9 +228,13 @@ const ShippingZoneRateDialog = withStyles(styles, { label={ variant === ShippingMethodTypeEnum.PRICE ? typedFormErrors.minimumOrderPrice || - i18n.t("Minimal Order Value") + intl.formatMessage({ + defaultMessage: "Minimal Order Value" + }) : typedFormErrors.minimumOrderWeight || - i18n.t("Minimal Order Weight") + intl.formatMessage({ + defaultMessage: "Minimal Order Weight" + }) } name={"minValue" as keyof FormData} type="number" @@ -219,9 +257,13 @@ const ShippingZoneRateDialog = withStyles(styles, { label={ variant === ShippingMethodTypeEnum.PRICE ? typedFormErrors.maximumOrderPrice || - i18n.t("Maximal Order Value") + intl.formatMessage({ + defaultMessage: "Maximal Order Value" + }) : typedFormErrors.maximumOrderWeight || - i18n.t("Maximal Order Weight") + intl.formatMessage({ + defaultMessage: "Maximal Order Weight" + }) } name={"maxValue" as keyof FormData} type="number" @@ -242,12 +284,18 @@ const ShippingZoneRateDialog = withStyles(styles, { className={classes.subheading} variant="subtitle1" > - {i18n.t("Rate")} + @@ -260,7 +308,10 @@ const ShippingZoneRateDialog = withStyles(styles, { error={!!typedFormErrors.price} fullWidth helperText={typedFormErrors.price} - label={i18n.t("Rate Price")} + label={intl.formatMessage({ + defaultMessage: "Rate Price", + description: "shipping method price" + })} name={"price" as keyof FormData} type="number" value={data.price} @@ -275,7 +326,7 @@ const ShippingZoneRateDialog = withStyles(styles, { {action === "create" - ? i18n.t("Create rate", { context: "button" }) - : i18n.t("Update rate", { context: "button" })} + ? intl.formatMessage({ + defaultMessage: "Create rate", + description: "button" + }) + : intl.formatMessage({ + defaultMessage: "Update rate", + description: "button" + })} diff --git a/src/shipping/components/ShippingZoneRates/ShippingZoneRates.tsx b/src/shipping/components/ShippingZoneRates/ShippingZoneRates.tsx index 2d3c41e7e..d99abc180 100644 --- a/src/shipping/components/ShippingZoneRates/ShippingZoneRates.tsx +++ b/src/shipping/components/ShippingZoneRates/ShippingZoneRates.tsx @@ -14,6 +14,7 @@ import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import EditIcon from "@material-ui/icons/Edit"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import IconButtonTableCell from "@saleor/components/IconButtonTableCell"; @@ -21,7 +22,6 @@ import Money from "@saleor/components/Money"; import MoneyRange from "@saleor/components/MoneyRange"; import Skeleton from "@saleor/components/Skeleton"; import WeightRange from "@saleor/components/WeightRange"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { ICONBUTTON_SIZE } from "../../../theme"; import { ShippingZoneDetailsFragment_shippingMethods } from "../../types/ShippingZoneDetailsFragment"; @@ -60,104 +60,127 @@ const ShippingZoneRates = withStyles(styles, { name: "ShippingZoneRates" })( onRateRemove, rates, variant - }: ShippingZoneRatesProps & WithStyles) => ( - - - {i18n.t("Add rate", { - context: "button" - })} - - } - /> -
- - - - {i18n.t("Name", { context: "object" })} - - - {variant === "price" - ? i18n.t("Value Range", { context: "object" }) - : i18n.t("Weight Range", { context: "object" })} - - - {i18n.t("Price", { context: "object" })} - - - - - - - {renderCollection( - rates, - rate => ( - onRateEdit(rate.id) : undefined} - > - - {maybe(() => rate.name, )} - - - {maybe( - () => - variant === "price" ? ( - - ) : ( - + }: ShippingZoneRatesProps & WithStyles) => { + const intl = useIntl(); + + return ( + + + + + } + /> +
+ + + + + + + {variant === "price" + ? intl.formatMessage({ + defaultMessage: "Value Range", + description: "shipping method price range" + }) + : intl.formatMessage({ + defaultMessage: "Weight Range", + description: "shipping method weight range" + })} + + + + + + + + + + {renderCollection( + rates, + rate => ( + onRateEdit(rate.id) : undefined} + > + + {maybe(() => rate.name, )} + + + {maybe( + () => + variant === "price" ? ( + + ) : ( + + ), + + )} + + + {maybe( + () => ( + ), - - )} - - - {maybe( - () => ( - - ), - - )} - - onRateEdit(rate.id)} - > - - - onRateRemove(rate.id)} - > - - - - ), - () => ( - - - {i18n.t("No shipping rates found")} - - - ) - )} - -
- - ) + + )} + + onRateEdit(rate.id)} + > + + + onRateRemove(rate.id)} + > + + + + ), + () => ( + + + + + + ) + )} + + + + ); + } ); ShippingZoneRates.displayName = "ShippingZoneRates"; export default ShippingZoneRates; diff --git a/src/shipping/components/ShippingZonesList/ShippingZonesList.tsx b/src/shipping/components/ShippingZonesList/ShippingZonesList.tsx index f38a21ab6..779383bda 100644 --- a/src/shipping/components/ShippingZonesList/ShippingZonesList.tsx +++ b/src/shipping/components/ShippingZonesList/ShippingZonesList.tsx @@ -14,13 +14,13 @@ import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; 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 { maybe, renderCollection } from "@saleor/misc"; import { ICONBUTTON_SIZE } from "@saleor/theme"; import { ListActions, ListProps } from "@saleor/types"; @@ -71,114 +71,127 @@ const ShippingZonesList = withStyles(styles, { name: "ShippingZonesList" })( toggle, toggleAll, toolbar - }: ShippingZonesListProps & WithStyles) => ( - - - {i18n.t("Add shipping zone", { - context: "button" - })} - - } - /> - - - - {i18n.t("Name", { context: "object" })} - - - {i18n.t("Countries", { context: "object" })} - - - - - - - - - - {renderCollection( - shippingZones, - shippingZone => { - const isSelected = shippingZone - ? isChecked(shippingZone.id) - : false; + }: ShippingZonesListProps & WithStyles) => { + const intl = useIntl(); - return ( - - - toggle(shippingZone.id)} - /> - - - {maybe( - () => shippingZone.name, - - )} - - - {maybe( - () => shippingZone.countries.length, - - )} - - - { - event.stopPropagation(); - onRemove(shippingZone.id); - }} - > - - + return ( + + + + + } + /> +
+ + + + + + + + + + + + + + + + {renderCollection( + shippingZones, + shippingZone => { + const isSelected = shippingZone + ? isChecked(shippingZone.id) + : false; + + return ( + + + toggle(shippingZone.id)} + /> + + + {maybe( + () => shippingZone.name, + + )} + + + {maybe( + () => shippingZone.countries.length, + + )} + + + { + event.stopPropagation(); + onRemove(shippingZone.id); + }} + > + + + + + ); + }, + () => ( + + + - ); - }, - () => ( - - - {i18n.t("No shipping zones found")} - - - ) - )} - -
-
- ) + ) + )} + + + + ); + } ); ShippingZonesList.displayName = "ShippingZonesList"; export default ShippingZonesList; diff --git a/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx b/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx index b9aa74b37..49dc9c600 100644 --- a/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx +++ b/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx @@ -1,10 +1,11 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListActions, PageListProps } from "@saleor/types"; import { WeightUnitsEnum } from "@saleor/types/globalTypes"; import { ShippingZoneFragment } from "../../types/ShippingZoneFragment"; @@ -21,27 +22,34 @@ export interface ShippingZonesListPageProps extends PageListProps, ListActions { const ShippingZonesListPage: React.StatelessComponent< ShippingZonesListPageProps -> = ({ defaultWeightUnit, disabled, onBack, onSubmit, ...listProps }) => ( - - {i18n.t("Configuration")} - - -
- -
-
- -
-
-
-); +> = ({ defaultWeightUnit, disabled, onBack, onSubmit, ...listProps }) => { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.configuration)} + + + +
+ +
+
+ +
+
+
+ ); +}; ShippingZonesListPage.displayName = "ShippingZonesListPage"; export default ShippingZonesListPage; diff --git a/src/shipping/index.tsx b/src/shipping/index.tsx index 6ba390e46..5b3b793e4 100644 --- a/src/shipping/index.tsx +++ b/src/shipping/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { shippingZoneAddPath, shippingZonePath, @@ -39,14 +40,26 @@ const ShippingZoneDetails: React.StatelessComponent< ); }; -export const ShippingRouter: React.StatelessComponent = () => ( - <> - - - - - - - -); +export const ShippingRouter: React.FC = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + ); +}; export default ShippingRouter; diff --git a/src/shipping/views/ShippingZoneCreate.tsx b/src/shipping/views/ShippingZoneCreate.tsx index b474dfdea..88ca78669 100644 --- a/src/shipping/views/ShippingZoneCreate.tsx +++ b/src/shipping/views/ShippingZoneCreate.tsx @@ -1,9 +1,10 @@ import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import ShippingZoneCreatePage from "../components/ShippingZoneCreatePage"; import { TypedCreateShippingZone } from "../mutations"; @@ -14,13 +15,12 @@ const ShippingZoneCreate: React.StatelessComponent<{}> = () => { const navigate = useNavigator(); const pushMessage = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onShippingZoneCreate = (data: CreateShippingZone) => { if (data.shippingZoneCreate.errors.length === 0) { pushMessage({ - text: i18n.t("Successfully created new shipping zone", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(shippingZoneUrl(data.shippingZoneCreate.shippingZone.id)); } diff --git a/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx b/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx index 48173f196..6f1784f1a 100644 --- a/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx +++ b/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx @@ -1,11 +1,11 @@ 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 useNavigator from "@saleor/hooks/useNavigator"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import ShippingZoneCountriesAssignDialog from "../../components/ShippingZoneCountriesAssignDialog"; @@ -43,6 +43,7 @@ const ShippingZoneDetailsDialogs: React.StatelessComponent< }) => { const navigate = useNavigator(); const shop = useShop(); + const intl = useIntl(); const closeModal = () => navigate(shippingZoneUrl(id), true); @@ -92,20 +93,22 @@ const ShippingZoneDetailsDialogs: React.StatelessComponent< }) } open={params.action === "remove-rate"} - title={i18n.t("Delete Shipping Method")} + title={intl.formatMessage({ + defaultMessage: "Delete Shipping Method", + description: "dialog header" + })} variant="delete" > - {{ name }}?", - { - context: "remove shipping method", - name: maybe(() => rate.name, "...") - } - ) - }} - /> + + rate.name, "...") + }} + /> + - {{ name }}?", - { - context: "remove shipping zone", - name: maybe(() => shippingZone.name) - } - ) - }} - /> + + {maybe(() => shippingZone.name, "...")} + }} + /> + - {{ name }} from this shipping zone?", - { - context: "unassign country", - name: maybe( - () => - shippingZone.countries.find( - country => country.code === params.id - ).country - ) - } - ) - }} - /> + + + {maybe( + () => + shippingZone.countries.find( + country => country.code === params.id + ).country, + "..." + )} + + ) + }} + /> + ); diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 46b72770e..34d87c403 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -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 "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import ShippingZoneDetailsPage from "../../components/ShippingZoneDetailsPage"; @@ -30,15 +31,14 @@ const ShippingZoneDetails: React.StatelessComponent< > = ({ id, params }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const closeModal = () => navigate(shippingZoneUrl(id)); const onShippingRateCreate = (data: CreateShippingRate) => { if (data.shippingPriceCreate.errors.length === 0) { notify({ - text: i18n.t("Successfully created rate", { - context: "shipping method" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); } @@ -47,9 +47,7 @@ const ShippingZoneDetails: React.StatelessComponent< const onShippingRateUpdate = (data: UpdateShippingRate) => { if (data.shippingPriceUpdate.errors.length === 0) { notify({ - text: i18n.t("Successfully updated rate", { - context: "shipping method" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); } @@ -58,9 +56,7 @@ const ShippingZoneDetails: React.StatelessComponent< const onShippingRateDelete = (data: DeleteShippingRate) => { if (data.shippingPriceDelete.errors.length === 0) { notify({ - text: i18n.t("Successfully deleted rate", { - context: "shipping method" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); } @@ -69,7 +65,7 @@ const ShippingZoneDetails: React.StatelessComponent< const onShippingZoneDelete = (data: DeleteShippingZone) => { if (data.shippingZoneDelete.errors.length === 0) { notify({ - text: i18n.t("Successfully deleted shipping zone") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(shippingZonesListUrl(), true); } @@ -78,7 +74,7 @@ const ShippingZoneDetails: React.StatelessComponent< const onShippingZoneUpdate = (data: UpdateShippingZone) => { if (data.shippingZoneUpdate.errors.length === 0) { notify({ - text: i18n.t("Successfully updated shipping zone") + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); } diff --git a/src/shipping/views/ShippingZonesList.tsx b/src/shipping/views/ShippingZonesList.tsx index 501ec532a..d15a80b0e 100644 --- a/src/shipping/views/ShippingZonesList.tsx +++ b/src/shipping/views/ShippingZonesList.tsx @@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText"; import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { configurationMenuUrl } from "@saleor/configuration"; @@ -13,7 +14,7 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import ShippingZonesListPage from "../components/ShippingZonesListPage"; @@ -50,6 +51,7 @@ export const ShippingZonesList: React.StatelessComponent< const { updateListSettings, settings } = useListSettings( ListViews.SHIPPING_METHODS_LIST ); + const intl = useIntl(); const paginationState = createPaginationState(settings.rowNumber, params); @@ -61,9 +63,7 @@ export const ShippingZonesList: React.StatelessComponent< ) => { if (data.shopSettingsUpdate.errors.length === 0) { notify({ - text: i18n.t("Updated default weight unit", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -81,9 +81,7 @@ export const ShippingZonesList: React.StatelessComponent< const handleShippingZoneDelete = (data: DeleteShippingZone) => { if (data.shippingZoneDelete.errors.length === 0) { notify({ - text: i18n.t("Updated default weight unit", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); refetch(); @@ -93,9 +91,7 @@ export const ShippingZonesList: React.StatelessComponent< const handleBulkDeleteShippingZone = (data: BulkDeleteShippingZone) => { if (data.shippingZoneBulkDelete.errors.length === 0) { notify({ - text: i18n.t("Removed shipping zones", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); closeModal(); reset(); @@ -205,8 +201,9 @@ export const ShippingZonesList: React.StatelessComponent< open={params.action === "remove"} confirmButtonState={deleteTransitionState} variant="delete" - title={i18n.t("Delete Shipping Zone", { - context: "modal title" + title={intl.formatMessage({ + defaultMessage: "Delete Shipping Zone", + description: "dialog header" })} onClose={closeModal} onConfirm={() => @@ -215,30 +212,32 @@ export const ShippingZonesList: React.StatelessComponent< }) } > - {{ name }} shipping zone?", - { - context: "shipping zone removal", - name: maybe( - () => - data.shippingZones.edges.find( - edge => edge.node.id === params.id - ).node.name, - "..." - ) - } - ) - }} - /> + + + {maybe( + () => + data.shippingZones.edges.find( + edge => edge.node.id === params.id + ).node.name, + "..." + )} + + ) + }} + /> + @@ -247,19 +246,23 @@ export const ShippingZonesList: React.StatelessComponent< }) } > - {{ number }} shipping zones?", - { - number: maybe( - () => params.ids.length.toString(), - "..." - ) - } - ) - }} - /> + + params.ids.length), + displayQuantity: ( + + {maybe(() => params.ids.length)} + + ) + }} + /> + ); diff --git a/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx b/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx index 966078c03..e5381037b 100644 --- a/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx +++ b/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx @@ -3,6 +3,7 @@ import CardContent from "@material-ui/core/CardContent"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import React from "react"; +import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import FormSpacer from "@saleor/components/FormSpacer"; @@ -12,7 +13,6 @@ import SingleAutocompleteSelectField, { } from "@saleor/components/SingleAutocompleteSelectField"; import { AddressTypeInput } from "@saleor/customers/types"; import { ChangeEvent } from "@saleor/hooks/useForm"; -import i18n from "@saleor/i18n"; import { FormErrors } from "@saleor/types"; import { SiteSettingsPageFormData } from "../SiteSettingsPage"; @@ -42,110 +42,131 @@ const SiteSettingsAddress = withStyles(styles, { name: "SiteSettingsAddress" })( errors, onChange, onCountryChange - }: SiteSettingsAddressProps) => ( - - - - { + const intl = useIntl(); + + return ( + + - - - - - - + + - - - - + - - - - - - ) + + + + + + + + + + + + + + + ); + } ); SiteSettingsAddress.displayName = "SiteSettingsAddress"; export default SiteSettingsAddress; diff --git a/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.tsx b/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.tsx index f3cf77d2b..f2e0700fc 100644 --- a/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.tsx +++ b/src/siteSettings/components/SiteSettingsDetails/SiteSettingsDetails.tsx @@ -2,10 +2,11 @@ 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 { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import FormSpacer from "@saleor/components/FormSpacer"; -import i18n from "../../../i18n"; +import { commonMessages } from "@saleor/intl"; import { SiteSettingsPageFormData } from "../SiteSettingsPage"; interface SiteSettingsDetailsProps { @@ -21,61 +22,68 @@ interface SiteSettingsDetailsProps { const SiteSettingsDetails: React.StatelessComponent< SiteSettingsDetailsProps -> = ({ data, disabled, errors, onChange }) => ( - - - - = ({ data, disabled, errors, onChange }) => { + const intl = useIntl(); + + return ( + + - - - - - - -); + + + + + + + + + ); +}; SiteSettingsDetails.displayName = "SiteSettingsDetails"; export default SiteSettingsDetails; diff --git a/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.tsx b/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.tsx index 8c4a60285..73545589b 100644 --- a/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.tsx +++ b/src/siteSettings/components/SiteSettingsKeyDialog/SiteSettingsKeyDialog.tsx @@ -5,12 +5,13 @@ 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 Form, { FormProps } from "@saleor/components/Form"; import { FormSpacer } from "@saleor/components/FormSpacer"; import SingleSelectField from "@saleor/components/SingleSelectField"; -import i18n from "../../../i18n"; -import { translatedAuthorizationKeyTypes } from "../../../misc"; +import { buttonMessages } from "@saleor/intl"; +import { authorizationKeyTypes } from "../../../misc"; import { AuthorizationKeyType } from "../../../types/globalTypes"; export interface SiteSettingsKeyDialogForm { @@ -31,26 +32,29 @@ export interface SiteSettingsKeyDialogProps const SiteSettingsKeyDialog: React.StatelessComponent< SiteSettingsKeyDialogProps > = ({ errors, initial, open, onClose, onSubmit }) => { - const keyTypes = translatedAuthorizationKeyTypes(); + const intl = useIntl(); + return ( {({ change, data, errors }) => ( <> - {i18n.t("Add New Authorization Key", { - context: "modal title" - })} + ({ - label: keyTypes[key], + choices={Object.keys(authorizationKeyTypes).map(key => ({ + label: authorizationKeyTypes[key], value: key }))} error={!!errors.keyType} - label={i18n.t("Authentication type", { - context: "input label" + label={intl.formatMessage({ + defaultMessage: "Authentication type", + description: "authentication provider name" })} hint={errors.keyType} name="type" @@ -61,8 +65,9 @@ const SiteSettingsKeyDialog: React.StatelessComponent< diff --git a/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.tsx b/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.tsx index 0a22686fd..a2eaaeadc 100644 --- a/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.tsx +++ b/src/siteSettings/components/SiteSettingsKeys/SiteSettingsKeys.tsx @@ -14,15 +14,11 @@ import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; -import { - maybe, - renderCollection, - translatedAuthorizationKeyTypes -} from "../../../misc"; +import { authorizationKeyTypes, maybe, renderCollection } from "../../../misc"; import { ICONBUTTON_SIZE } from "../../../theme"; import { AuthorizationKeyType } from "../../../types/globalTypes"; import { SiteSettings_shop_authorizationKeys } from "../../types/SiteSettings"; @@ -46,12 +42,14 @@ interface SiteSettingsKeysProps extends WithStyles { const SiteSettingsKeys = withStyles(styles, { name: "SiteSettingsKeys" })( ({ classes, disabled, keys, onAdd, onRemove }: SiteSettingsKeysProps) => { - const keyTypes = translatedAuthorizationKeyTypes(); + const intl = useIntl(); + return ( - {i18n.t("Add key", { - context: "button" - })} + } /> @@ -70,10 +66,16 @@ const SiteSettingsKeys = withStyles(styles, { name: "SiteSettingsKeys" })( - {i18n.t("Authentication Type", { context: "table header" })} + - {i18n.t("Key", { context: "table header" })} + @@ -88,7 +90,7 @@ const SiteSettingsKeys = withStyles(styles, { name: "SiteSettingsKeys" })( > {maybe( - () => keyTypes[key.name], + () => authorizationKeyTypes[key.name], )} @@ -104,7 +106,12 @@ const SiteSettingsKeys = withStyles(styles, { name: "SiteSettingsKeys" })( ), () => ( - {i18n.t("No keys")} + + + ) )} diff --git a/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx b/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx index 794b7ac1a..6b90808de 100644 --- a/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx +++ b/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx @@ -1,5 +1,6 @@ import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; @@ -9,10 +10,10 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { UserError } from "@saleor/types"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { mapCountriesToChoices } from "@saleor/utils/maps"; -import i18n from "../../../i18n"; import { maybe } from "../../../misc"; import { AuthorizationKeyType } from "../../../types/globalTypes"; import { SiteSettings_shop } from "../../types/SiteSettings"; @@ -59,6 +60,7 @@ const SiteSettingsPage: React.StatelessComponent = ({ onKeyRemove, onSubmit }) => { + const intl = useIntl(); const [displayCountry, setDisplayCountry] = useStateFromProps( maybe(() => shop.companyAddress.country.code, "") ); @@ -96,14 +98,16 @@ const SiteSettingsPage: React.StatelessComponent = ({ return ( - {i18n.t("Configuration")} + + {intl.formatMessage(sectionNames.configuration)} + - {i18n.t("Site Settings")} + + {intl.formatMessage(sectionNames.siteSettings)} + = ({ onChange={change} /> - {i18n.t("Company information")} + = ({ onCountryChange={handleCountryChange} /> - {i18n.t("Authentication keys")} + = ({ }) => { const navigate = useNavigator(); const notify = useNotifier(); + const intl = useIntl(); const handleAddKeySuccess = (data: AuthorizationKeyAdd) => { if (!maybe(() => data.authorizationKeyAdd.errors.length)) { notify({ - text: i18n.t("Authorization key added", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(siteSettingsUrl()); } @@ -47,16 +48,18 @@ export const SiteSettings: React.StatelessComponent = ({ const handleDeleteKeySuccess = (data: AuthorizationKeyDelete) => { if (!maybe(() => data.authorizationKeyDelete.errors.length)) { notify({ - text: i18n.t("Authorization key deleted", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } else { notify({ - text: i18n.t("Could not delete authorization key: {{ message }}", { - context: "notification", - message: data.authorizationKeyDelete.errors[0].message - }) + text: intl.formatMessage( + { + defaultMessage: "Could not delete authorization key: {errorMessage}" + }, + { + errorMessage: data.authorizationKeyDelete.errors[0].message + } + ) }); } }; @@ -70,9 +73,7 @@ export const SiteSettings: React.StatelessComponent = ({ data.shopAddressUpdate.errors.length === 0) ) { notify({ - text: i18n.t("Site settings updated", { - context: "notification" - }) + text: intl.formatMessage(commonMessages.savedChanges) }); } }; @@ -166,7 +167,9 @@ export const SiteSettings: React.StatelessComponent = ({ return ( <> - + ( - - - {({ change, data, errors: formErrors, hasChanged }) => ( - <> - {i18n.t("Add Staff Member")} - -
+ }: StaffAddMemberDialogProps) => { + const intl = useIntl(); + + return ( + + + {({ change, data, errors: formErrors, hasChanged }) => ( + <> + + + + +
+ + +
+ - +
+ + + + + + + + -
- - -
-
- - - {i18n.t("Permissions")} - - - {i18n.t( - "Expand or restrict user’s permissions to access certain part of saleor system." - )} - - - - - - - {i18n.t("Send invite", { context: "button" })} - - - - )} - -
- ) +
+ + + + + + + + )} + +
+ ); + } ); StaffAddMemberDialog.displayName = "StaffAddMemberDialog"; export default StaffAddMemberDialog; diff --git a/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx b/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx index a104b703b..66c67179f 100644 --- a/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx +++ b/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; @@ -8,7 +9,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 "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { getUserName, maybe } from "../../../misc"; import { PermissionEnum } from "../../../types/globalTypes"; import { @@ -57,6 +58,8 @@ const StaffDetailsPage: React.StatelessComponent = ({ onImageUpload, onSubmit }: StaffDetailsPageProps) => { + const intl = useIntl(); + const initialForm: FormData = { email: maybe(() => staffMember.email, ""), firstName: maybe(() => staffMember.firstName, ""), @@ -78,7 +81,9 @@ const StaffDetailsPage: React.StatelessComponent = ({
{({ data, change, hasChanged, submit }) => ( - {i18n.t("Staff Members")} + + {intl.formatMessage(sectionNames.staff)} +
diff --git a/src/staff/components/StaffList/StaffList.tsx b/src/staff/components/StaffList/StaffList.tsx index a3c67c56a..eeefb9f97 100644 --- a/src/staff/components/StaffList/StaffList.tsx +++ b/src/staff/components/StaffList/StaffList.tsx @@ -14,10 +14,10 @@ import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import Skeleton from "@saleor/components/Skeleton"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "@saleor/i18n"; import { getUserInitials, getUserName, @@ -80,97 +80,114 @@ const StaffList = withStyles(styles, { name: "StaffList" })( onRowClick, pageInfo, staffMembers - }: StaffListProps) => ( - - - - - - {i18n.t("Name", { context: "object" })} - - - {i18n.t("Email Address", { context: "object" })} - - - - - - - - - - {renderCollection( - staffMembers, - staffMember => ( - - -
- {maybe(() => staffMember.avatar.url) ? ( - staffMember.avatar.url)} - /> - ) : ( -
- {getUserInitials(staffMember)} -
- )} -
- - {getUserName(staffMember) || } - - + }: StaffListProps) => { + const intl = useIntl(); + + return ( + +
+ + + + + + + + + + + + + + + + + {renderCollection( + staffMembers, + staffMember => ( + + +
+ {maybe(() => staffMember.avatar.url) ? ( + staffMember.avatar.url)} + /> + ) : ( +
+ + {getUserInitials(staffMember)} + +
+ )} +
+ + {getUserName(staffMember) || } + + + {maybe( + () => + staffMember.isActive + ? intl.formatMessage({ + defaultMessage: "Active", + description: "staff member status" + }) + : intl.formatMessage({ + defaultMessage: "Inactive", + description: "staff member status" + }), + + )} + +
+ {maybe( - () => - staffMember.isActive - ? i18n.t("Active", { context: "status" }) - : i18n.t("Inactive", { context: "status" }), + () => staffMember.email, )} - - - - {maybe( - () => staffMember.email, - - )} - -
- ), - () => ( - - - {i18n.t("No staff members found")} - - - ) - )} -
-
-
- ) + + + ), + () => ( + + + + + + ) + )} + + + + ); + } ); StaffList.displayName = "StaffList"; export default StaffList; diff --git a/src/staff/components/StaffListPage/StaffListPage.tsx b/src/staff/components/StaffListPage/StaffListPage.tsx index 73ebd20e0..04e251d8b 100644 --- a/src/staff/components/StaffListPage/StaffListPage.tsx +++ b/src/staff/components/StaffListPage/StaffListPage.tsx @@ -1,11 +1,12 @@ import Button from "@material-ui/core/Button"; import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { Container } from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "@saleor/i18n"; +import { sectionNames } from "@saleor/intl"; import { ListProps } from "@saleor/types"; import { StaffList_staffUsers_edges_node } from "../../types/StaffList"; import StaffList from "../StaffList/StaffList"; @@ -21,22 +22,31 @@ const StaffListPage: React.StatelessComponent = ({ onAdd, onBack, ...listProps -}) => ( - - {i18n.t("Configuration")} - - - - - -); +}) => { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.configuration)} + + + + + + + ); +}; StaffListPage.displayName = "StaffListPage"; export default StaffListPage; diff --git a/src/staff/components/StaffPermissions/StaffPermissions.tsx b/src/staff/components/StaffPermissions/StaffPermissions.tsx index aea41e7bb..0db9cb39e 100644 --- a/src/staff/components/StaffPermissions/StaffPermissions.tsx +++ b/src/staff/components/StaffPermissions/StaffPermissions.tsx @@ -8,11 +8,11 @@ import { } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { StaffMemberDetails_shop_permissions } from "../../types/StaffMemberDetails"; const styles = (theme: Theme) => @@ -47,6 +47,8 @@ const StaffPermissions = withStyles(styles, { name: "StaffPermissions" })( permissions, onChange }: StaffPermissionsProps) => { + const intl = useIntl(); + const handleFullAccessChange = (event: React.ChangeEvent) => onChange(event, () => onChange({ @@ -68,19 +70,23 @@ const StaffPermissions = withStyles(styles, { name: "StaffPermissions" })( }; return ( - + - {i18n.t( - "Expand or restrict user's permissions to access certain part of saleor system." - )} +
{ + const intl = useIntl(); const imgInputAnchor = React.createRef(); + const clickImgInput = () => imgInputAnchor.current.click(); + return ( - +
@@ -143,10 +152,16 @@ const StaffProperties = withStyles(styles, { name: "StaffProperties" })(
- {i18n.t("Change photo")} + - {i18n.t("Delete photo")} +
= ({ data, disabled, onChange -}) => ( - - - - - {i18n.t("If you want to disable this account uncheck the box below")} - - { + const intl = useIntl(); + + return ( + + - - -); + + + + + + + + ); +}; StaffStatus.displayName = "StaffStatus"; export default StaffStatus; diff --git a/src/staff/index.tsx b/src/staff/index.tsx index 66dea74b0..84470608f 100644 --- a/src/staff/index.tsx +++ b/src/staff/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { staffListPath, StaffListUrlQueryParams, @@ -38,14 +39,18 @@ const StaffDetails: React.StatelessComponent< ); }; -const Component = () => ( - <> - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + ); +}; export default Component; diff --git a/src/staff/views/StaffDetails.tsx b/src/staff/views/StaffDetails.tsx index e71e67f9a..2ae48ba1b 100644 --- a/src/staff/views/StaffDetails.tsx +++ b/src/staff/views/StaffDetails.tsx @@ -1,12 +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 { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useUser from "@saleor/hooks/useUser"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import StaffDetailsPage from "../components/StaffDetailsPage/StaffDetailsPage"; import { @@ -38,6 +39,7 @@ export const StaffDetails: React.StatelessComponent = ({ const navigate = useNavigator(); const notify = useNotifier(); const user = useUser(); + const intl = useIntl(); return ( = ({ const handleStaffMemberUpdate = (data: StaffMemberUpdate) => { if (!maybe(() => data.staffUpdate.errors.length !== 0)) { notify({ - text: i18n.t("Succesfully updated staff member account") + text: intl.formatMessage(commonMessages.savedChanges) }); } }; const handleStaffMemberDelete = (data: StaffMemberDelete) => { if (!maybe(() => data.staffDelete.errors.length !== 0)) { notify({ - text: i18n.t("Succesfully removed staff member") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(staffListUrl()); } @@ -64,14 +66,14 @@ export const StaffDetails: React.StatelessComponent = ({ const handleStaffMemberAvatarUpdate = (data: StaffAvatarUpdate) => { if (!maybe(() => data.userAvatarUpdate.errors.length !== 0)) { notify({ - text: i18n.t("Succesfully updated staff member avatar") + text: intl.formatMessage(commonMessages.savedChanges) }); } }; const handleStaffMemberAvatarDelete = (data: StaffAvatarDelete) => { if (!maybe(() => data.userAvatarDelete.errors.length !== 0)) { notify({ - text: i18n.t("Succesfully removed staff member avatar") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(staffMemberDetailsUrl(id)); } @@ -167,7 +169,10 @@ export const StaffDetails: React.StatelessComponent = ({ /> @@ -175,20 +180,21 @@ export const StaffDetails: React.StatelessComponent = ({ } onConfirm={deleteStaffMember} > - {{ email }} from staff members?", - { - email: maybe(() => data.user.email) - } - ) - }} - /> + + data.user.email, "...") + }} + /> + @@ -196,16 +202,18 @@ export const StaffDetails: React.StatelessComponent = ({ } onConfirm={deleteStaffAvatar} > - {{ email }} avatar?", - { - email: maybe(() => data.user.email) - } - ) - }} - /> + + + {maybe(() => data.user.email, "...")} + + ) + }} + /> + ); diff --git a/src/staff/views/StaffList.tsx b/src/staff/views/StaffList.tsx index a730d8695..0cc4ad33e 100644 --- a/src/staff/views/StaffList.tsx +++ b/src/staff/views/StaffList.tsx @@ -6,9 +6,10 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; +import { useIntl } from "react-intl"; import { configurationMenuUrl } from "@saleor/configuration"; -import i18n from "@saleor/i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import StaffAddMemberDialog, { @@ -37,6 +38,7 @@ export const StaffList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.STAFF_MEMBERS_LIST ); + const intl = useIntl(); const closeModal = () => navigate( @@ -55,7 +57,7 @@ export const StaffList: React.StatelessComponent = ({ const handleStaffMemberAddSuccess = (data: StaffMemberAdd) => { if (data.staffCreate.errors.length === 0) { notify({ - text: i18n.t("Succesfully added staff member") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate(staffMemberDetailsUrl(data.staffCreate.user.id)); } diff --git a/src/storybook/.babelrc b/src/storybook/.babelrc deleted file mode 100644 index 2b7bafa5f..000000000 --- a/src/storybook/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@babel/preset-env", "@babel/preset-react"] -} diff --git a/src/storybook/Decorator.tsx b/src/storybook/Decorator.tsx index 573cde8b1..c82b0b336 100644 --- a/src/storybook/Decorator.tsx +++ b/src/storybook/Decorator.tsx @@ -1,25 +1,31 @@ import React from "react"; +import { IntlProvider } from "react-intl"; +import { RawLocaleProvider } from "@saleor/components/Locale"; import { Provider as DateProvider } from "../components/Date/DateContext"; import { MessageManager } from "../components/messages"; import ThemeProvider from "../components/Theme"; import { TimezoneProvider } from "../components/Timezone"; export const Decorator = storyFn => ( - - - - -
- {storyFn()} -
-
-
-
-
+ + + + + + +
+ {storyFn()} +
+
+
+
+
+
+
); export default Decorator; diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 609c36f13..0b6f69afe 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -76,7 +76,7 @@ exports[`Storyshots Generics / AddressEdit default 1`] = ` class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - First name + First Name
- Last name + Last Name
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse -
- malesuada lacus ex, sit amet blandit leo lobortis eget. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.

@@ -5340,9 +5338,7 @@ exports[`Storyshots Generics / Timeline with order notes 1`] = `

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse -
- malesuada lacus ex, sit amet blandit leo lobortis eget. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.

@@ -6427,7 +6423,7 @@ exports[`Storyshots Views / Attributes / Attribute details create 1`] = ` - General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- Add attribute + Add attribute
- Sorry, your username and/or password are incorrect. -
- Please try again. + Sorry, your username and/or password are incorrect. Please try again.
- Email + E-mail Address
- Email + E-mail Address
- Add category + Add category - Add category + Add category - Add category + Add category
- Add Category + Create New Category
- General information + General Informations
- Name + Category Name
- Description + Category Description
- Add search engine title and description to make this product easier to find + Add search engine title and description to make this category easier to find

@@ -13751,7 +13745,7 @@ exports[`Storyshots Views / Categories / Create category default 1`] = `
- Add Category + Create New Category
- General information + General Informations
- Name + Category Name
- Description + Category Description
- Add search engine title and description to make this product easier to find + Add search engine title and description to make this category easier to find

@@ -14225,7 +14219,7 @@ exports[`Storyshots Views / Categories / Update category default 1`] = ` - General information + General Informations
- Name + Category Name
- Description + Category Description
@@ -14951,7 +14945,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -15080,7 +15074,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id CategoryList-colProducts-id" scope="col" > - No. Products + No. of Products @@ -15219,7 +15213,7 @@ exports[`Storyshots Views / Categories / Update category loading 1`] = ` - General information + General Informations
- Name + Category Name
- Description + Category Description
@@ -15635,7 +15629,7 @@ Ctrl + K" >
- No. Products + No. of Products @@ -15962,7 +15956,7 @@ exports[`Storyshots Views / Categories / Update category no background 1`] = ` - General information + General Informations
- Name + Category Name
- Description + Category Description
@@ -16688,7 +16682,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -16817,7 +16811,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id CategoryList-colProducts-id" scope="col" > - No. Products + No. of Products @@ -16951,7 +16945,7 @@ exports[`Storyshots Views / Categories / Update category no products 1`] = ` - General information + General Informations
- Name + Category Name
- Description + Category Description
@@ -17677,7 +17671,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -17969,7 +17963,7 @@ exports[`Storyshots Views / Categories / Update category no subcategories 1`] = - General information + General Informations
- Name + Category Name
- Description + Category Description
@@ -18695,7 +18689,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -18824,7 +18818,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id CategoryList-colProducts-id" scope="col" > - No. Products + No. of Products @@ -18958,7 +18952,7 @@ exports[`Storyshots Views / Categories / Update category products 1`] = ` - General information + General Informations
- Name + Category Name
- Description + Category Description
@@ -19684,7 +19678,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -20586,7 +20580,7 @@ exports[`Storyshots Views / Collections / Collection details default 1`] = ` - General information + General Informations
@@ -21310,7 +21304,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -22033,7 +22027,7 @@ exports[`Storyshots Views / Collections / Collection details loading 1`] = ` - General information + General Informations
@@ -22447,7 +22441,7 @@ Ctrl + K" >
- General information + General Informations
@@ -23713,7 +23707,7 @@ Ctrl + K"

- Optional + (Optional)

@@ -24152,7 +24146,7 @@ exports[`Storyshots Views / Collections / Collection list default 1`] = ` class="MuiTableCell-root-id MuiTableCell-head-id CollectionList-colProducts-id" scope="col" > - No. Products + No. of Products - No. Products + No. of Products - General information + General Informations
@@ -25517,7 +25511,7 @@ exports[`Storyshots Views / Collections / Create collection loading 1`] = ` - General information + General Informations
@@ -26415,7 +26409,7 @@ exports[`Storyshots Views / Configuration default 1`] = `

- Manage how you ship out orders. + Manage how you ship out orders

@@ -27017,7 +27011,7 @@ exports[`Storyshots Views / Customers / Address Book default 1`] = `
- Tom Cooper Address Book + Tom Cooper's Address Book
- Delete + Remove
@@ -27282,7 +27276,7 @@ exports[`Storyshots Views / Customers / Address Book default 1`] = ` - Delete + Remove
@@ -27306,12 +27300,7 @@ exports[`Storyshots Views / Customers / Address Book loading 1`] = `
- - ‌ - + ...'s Address Book
- Delete + Remove
@@ -27637,7 +27626,7 @@ exports[`Storyshots Views / Customers / Create customer default 1`] = ` class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id" data-shrink="false" > - Email address + E-mail Address
- First name + First Name
- Last name + Last Name
- Email address + E-mail Address
- First name + First Name
- Last name + Last Name
- Email address + E-mail Address
- First name + First Name
- Last name + Last Name
- General Information + General Informations @@ -29898,7 +29887,7 @@ exports[`Storyshots Views / Customers / Customer details default 1`] = ` class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations @@ -30405,7 +30394,7 @@ exports[`Storyshots Views / Customers / Customer details different addresses 1`] class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations @@ -30959,7 +30948,7 @@ exports[`Storyshots Views / Customers / Customer details form errors 1`] = ` class="MuiFormLabel-root-id MuiFormLabel-error-id MuiInputLabel-error-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations - E-mail + E-mail Address
- General Information + General Informations @@ -31965,7 +31954,7 @@ exports[`Storyshots Views / Customers / Customer details never logged 1`] = ` class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations @@ -32466,7 +32455,7 @@ exports[`Storyshots Views / Customers / Customer details never placed order 1`] class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations @@ -32967,7 +32956,7 @@ exports[`Storyshots Views / Customers / Customer details no address at all 1`] = class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations @@ -33449,7 +33438,7 @@ exports[`Storyshots Views / Customers / Customer details no default billing addr class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- General Information + General Informations @@ -33956,7 +33945,7 @@ exports[`Storyshots Views / Customers / Customer details no default shipping add class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id" data-shrink="true" > - E-mail + E-mail Address
- Add customer + Add customer - Add customer + Add customer - Add customer + Add customer - General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- General Information + General Informations
- Product name + Product Name - Add sale + Add Sale
- Usage Limit + Usage Limit
- General Information + General Informations
- Usage Limit + Usage Limit
- General Information + General Informations
- Specific Products + Specific products
@@ -43022,7 +43011,7 @@ exports[`Storyshots Views / Discounts / Voucher details default 1`] = ` - Usage Limit + Usage Limit
- General Information + General Informations
- Specific Products + Specific products
@@ -44011,7 +44000,7 @@ exports[`Storyshots Views / Discounts / Voucher details form errors 1`] = ` - Usage Limit + Usage Limit
- General Information + General Informations
- Specific Products + Specific products
@@ -44974,7 +44963,7 @@ exports[`Storyshots Views / Discounts / Voucher details loading 1`] = ` - Usage Limit + Usage Limit
- - 1 Orders - - are ready to fulfill + + 1 + + Orders are ready to fulfill

- 1 Orders + One ordered

- - 1 Orders - - are ready to fulfill + + 1 + + Orders are ready to fulfill

  • - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - Add Menu + Add Menu
    - Cancelled (1) + Fulfilled (1)

    @@ -51719,7 +51708,7 @@ exports[`Storyshots Views / Orders / Order details cancelled 1`] = `

    - Cancelled (1) + Fulfilled (1)

    @@ -65106,7 +65095,7 @@ exports[`Storyshots Views / Orders / Order draft default 1`] = ` - Order details + Order Details

    - Order details + Order Details
    - Order details + Order Details
    - Create order + Create order
    - General Information + General Informations
    - General Information + General Informations
    - Information + General Informations
    - Information + General Informations
    - Information + General Informations
    - Information + General Informations
    - Information + General Informations
    - Information + General Informations
    - Information + General Informations
    - Product types + Product Types
    - Product types + Product Types
    - General information + General Informations
    - General information + General Informations
    - General information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General information + General Informations
    - General information + General Informations
    - General information + General Informations
    - General information + General Informations
    - All photos + All Photos
    - All photos + All Photos
    - Add product + Add Product
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - General Information + General Informations
    - E-mail + E-mail Address
    - E-mail + E-mail Address
    - E-mail + E-mail Address
    - E-mail + E-mail Address
    - Staff members + Staff Members
    - Staff members + Staff Members
    undefined, onConfirm: () => undefined, open: true, - quantity: "5" + quantity: 5 }; storiesOf("Attributes / Delete multiple attributes", module) diff --git a/src/storybook/stories/configuration/ConfigurationPage.tsx b/src/storybook/stories/configuration/ConfigurationPage.tsx index 36576cb33..24fac7643 100644 --- a/src/storybook/stories/configuration/ConfigurationPage.tsx +++ b/src/storybook/stories/configuration/ConfigurationPage.tsx @@ -1,11 +1,10 @@ -import { Omit } from "@material-ui/core"; import { storiesOf } from "@storybook/react"; import React from "react"; +import { useIntl } from "react-intl"; -import { configurationMenu } from "../../../configuration"; -import ConfigurationPage, { - ConfigurationPageProps -} from "../../../configuration/ConfigurationPage"; +import { User } from "@saleor/auth/types/User"; +import { createConfigurationMenu } from "../../../configuration"; +import ConfigurationPage from "../../../configuration/ConfigurationPage"; import { staffMember } from "../../../staff/fixtures"; import Decorator from "../../Decorator"; @@ -23,20 +22,27 @@ const user = { note: null, permissions: staffMember.permissions }; -const props: Omit = { - menu: configurationMenu, - onSectionClick: () => undefined, - user -}; -const partialAccessProps: Omit = { - ...props, - user: { - ...user, - permissions: user.permissions.slice(2, 6) - } + +const Story: React.FC<{ user: User }> = ({ user }) => { + const intl = useIntl(); + + return ( + undefined} + user={user} + /> + ); }; storiesOf("Views / Configuration", module) .addDecorator(Decorator) - .add("default", () => ) - .add("partial access", () => ); + .add("default", () => ) + .add("partial access", () => ( + + )); diff --git a/src/storybook/stories/home/HomePage.tsx b/src/storybook/stories/home/HomePage.tsx index e024ced34..9a599ed59 100644 --- a/src/storybook/stories/home/HomePage.tsx +++ b/src/storybook/stories/home/HomePage.tsx @@ -9,7 +9,7 @@ import Decorator from "../../Decorator"; const shop = shopFixture(placeholderImage); -const HomePageProps: Omit = { +const homePageProps: Omit = { activities: shop.activities.edges.map(edge => edge.node), onOrdersToCaptureClick: () => undefined, onOrdersToFulfillClick: () => undefined, @@ -26,10 +26,10 @@ const HomePageProps: Omit = { storiesOf("Views / HomePage", module) .addDecorator(Decorator) - .add("default", () => ) + .add("default", () => ) .add("loading", () => ( )) .add("no data", () => ( - + )); diff --git a/src/storybook/stories/productTypes/ProductTypeBulkAttributeUnassignDialog.tsx b/src/storybook/stories/productTypes/ProductTypeBulkAttributeUnassignDialog.tsx index 1c3941025..97e60fbe7 100644 --- a/src/storybook/stories/productTypes/ProductTypeBulkAttributeUnassignDialog.tsx +++ b/src/storybook/stories/productTypes/ProductTypeBulkAttributeUnassignDialog.tsx @@ -7,7 +7,7 @@ import ProductTypeBulkAttributeUnassignDialog, { import Decorator from "../../Decorator"; const props: ProductTypeBulkAttributeUnassignDialogProps = { - attributeQuantity: "4", + attributeQuantity: 4, confirmButtonState: "default", onClose: () => undefined, onConfirm: () => undefined, diff --git a/src/storybook/webpack.config.js b/src/storybook/webpack.config.js index 1e2cdb04b..9c94ff6cb 100644 --- a/src/storybook/webpack.config.js +++ b/src/storybook/webpack.config.js @@ -1,15 +1,18 @@ /* eslint-disable */ +const path = require("path"); const CheckerPlugin = require("fork-ts-checker-webpack-plugin"); const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); +const resolve = resolvePath => path.resolve(__dirname, resolvePath); + module.exports = ({ config }) => { config.module.rules.push({ - test: /\.tsx?$/, + test: /\.(jsx?|tsx?)$/, exclude: /node_modules/, - loader: "ts-loader", + loader: "babel-loader", options: { - experimentalWatchApi: true, - transpileOnly: true + configFile: resolve("../../babel.config.js"), + envName: "storybook" } }); config.optimization.removeAvailableModules = false; diff --git a/src/taxes/components/CountryList/CountryList.tsx b/src/taxes/components/CountryList/CountryList.tsx index 0af6a69eb..bc01c1b85 100644 --- a/src/taxes/components/CountryList/CountryList.tsx +++ b/src/taxes/components/CountryList/CountryList.tsx @@ -7,9 +7,9 @@ import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage } from "react-intl"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; import { CountryList_shop_countries } from "../../types/CountryList"; @@ -34,13 +34,13 @@ const CountryList = withStyles(styles, { name: "CountryList" })( - {i18n.t("Country Code", { context: "object" })} + - {i18n.t("Country Name", { context: "object" })} + - {i18n.t("Reduced Tax Rates", { context: "object" })} + @@ -73,7 +73,7 @@ const CountryList = withStyles(styles, { name: "CountryList" })( () => ( - {i18n.t("No countries found")} + ) diff --git a/src/taxes/components/CountryListPage/CountryListPage.tsx b/src/taxes/components/CountryListPage/CountryListPage.tsx index a9ca63481..2d6c0af50 100644 --- a/src/taxes/components/CountryListPage/CountryListPage.tsx +++ b/src/taxes/components/CountryListPage/CountryListPage.tsx @@ -1,11 +1,12 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import { Container } from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { CountryList_shop } from "../../types/CountryList"; import CountryList from "../CountryList"; @@ -33,6 +34,8 @@ const CountryListPage: React.StatelessComponent = ({ onSubmit, onTaxFetch }) => { + const intl = useIntl(); + const initialForm: FormData = { chargeTaxesOnShipping: maybe(() => shop.chargeTaxesOnShipping, false), includeTax: maybe(() => shop.includeTaxesInPrices, false), @@ -42,8 +45,15 @@ const CountryListPage: React.StatelessComponent = ({ {({ change, data, submit }) => ( - {i18n.t("Configuration")} - + + {intl.formatMessage(sectionNames.configuration)} + +
    ) => { - const taxRates = translatedTaxRates(); + const intl = useIntl(); + + const taxRates = translatedTaxRates(intl); return ( - {i18n.t("Taxes")} + + {intl.formatMessage(sectionNames.taxes)} + @@ -56,10 +66,10 @@ const CountryTaxesPage = withStyles(styles, { name: "CountryTaxesPage" })( - {i18n.t("Category", { context: "object" })} + - {i18n.t("Tax Rate", { context: "object" })} + @@ -87,7 +97,7 @@ const CountryTaxesPage = withStyles(styles, { name: "CountryTaxesPage" })( () => ( - {i18n.t("No reduced tax categories found")} + ) diff --git a/src/taxes/components/TaxConfiguration/TaxConfiguration.tsx b/src/taxes/components/TaxConfiguration/TaxConfiguration.tsx index 483678efc..a044e71f1 100644 --- a/src/taxes/components/TaxConfiguration/TaxConfiguration.tsx +++ b/src/taxes/components/TaxConfiguration/TaxConfiguration.tsx @@ -4,12 +4,13 @@ import CardActions from "@material-ui/core/CardActions"; import CardContent from "@material-ui/core/CardContent"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; 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 "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { FormData } from "../CountryListPage"; interface TaxConfigurationProps { @@ -34,40 +35,54 @@ export const TaxConfiguration = withStyles(styles, { disabled, onChange, onTaxFetch - }: TaxConfigurationProps & WithStyles) => ( - - - - - - - - -
    - - - -
    - ) + }: TaxConfigurationProps & WithStyles) => { + const intl = useIntl(); + + return ( + + + + + + + + +
    + + + +
    + ); + } ); export default TaxConfiguration; diff --git a/src/taxes/index.tsx b/src/taxes/index.tsx index 3768609d1..ecdeee595 100644 --- a/src/taxes/index.tsx +++ b/src/taxes/index.tsx @@ -1,8 +1,9 @@ import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { countryListPath, countryTaxRatesPath } from "./urls"; import CountryList from "./views/CountryList"; import CountryTaxesComponent, { @@ -13,18 +14,22 @@ const CountryTaxes: React.StatelessComponent< RouteComponentProps > = ({ match }) => ; -const Component = () => ( - <> - - - - - - -); +const Component = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + ); +}; export default Component; diff --git a/src/translations/components/TranslationFields/TranslationFields.tsx b/src/translations/components/TranslationFields/TranslationFields.tsx index 883eff450..30048d986 100644 --- a/src/translations/components/TranslationFields/TranslationFields.tsx +++ b/src/translations/components/TranslationFields/TranslationFields.tsx @@ -17,7 +17,9 @@ import Hr from "@saleor/components/Hr"; import Skeleton from "@saleor/components/Skeleton"; import classNames from "classnames"; import React from "react"; -import i18n from "../../../i18n"; +import { FormattedMessage } from "react-intl"; + +import { buttonMessages } from "@saleor/intl"; import TranslationFieldsLong from "./TranslationFieldsLong"; import TranslationFieldsRich from "./TranslationFieldsRich"; import TranslationFieldsShort from "./TranslationFieldsShort"; @@ -138,12 +140,13 @@ const TranslationFields = withStyles(styles, { name: "TranslationFields" })( - {i18n.t("Original String")} + - {i18n.t("Translation", { - context: "translation to language" - })} + {fields.map(field => ( @@ -153,7 +156,7 @@ const TranslationFields = withStyles(styles, { name: "TranslationFields" })(
    @@ -231,16 +234,16 @@ const TranslationFields = withStyles(styles, { name: "TranslationFields" })( ) : ( - {i18n.t( - "{{ fieldQuantity }} Translations, {{ translatedFieldQuantity }} Completed", - { - fieldQuantity: fields.length, - translatedFieldQuantity: fields.reduce( + acc + +(field.translation !== null), 0 ) - } - )} + }} + /> )} diff --git a/src/translations/components/TranslationFields/TranslationFieldsLong.tsx b/src/translations/components/TranslationFields/TranslationFieldsLong.tsx index 5729ff779..9a4d865ed 100644 --- a/src/translations/components/TranslationFields/TranslationFieldsLong.tsx +++ b/src/translations/components/TranslationFields/TranslationFieldsLong.tsx @@ -1,10 +1,10 @@ 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 { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; -import i18n from "../../../i18n"; import TranslationFieldsSave from "./TranslationFieldsSave"; interface TranslationFieldsLongProps { @@ -23,8 +23,10 @@ const TranslationFieldsLong: React.FC = ({ saveButtonState, onDiscard, onSubmit -}) => - edit ? ( +}) => { + const intl = useIntl(); + + return edit ? ( onSubmit(data.translation)} @@ -35,7 +37,9 @@ const TranslationFieldsLong: React.FC = ({ disabled={disabled} fullWidth multiline - label={i18n.t("Translation")} + label={intl.formatMessage({ + defaultMessage: "Translation" + })} name="translation" value={data.translation} onChange={change} @@ -50,10 +54,11 @@ const TranslationFieldsLong: React.FC = ({ ) : initial === null ? ( - {i18n.t("No translation yet")} + ) : ( {initial} ); +}; TranslationFieldsLong.displayName = "TranslationFieldsLong"; export default TranslationFieldsLong; diff --git a/src/translations/components/TranslationFields/TranslationFieldsRich.tsx b/src/translations/components/TranslationFields/TranslationFieldsRich.tsx index 108eed7c4..e9b3c82ee 100644 --- a/src/translations/components/TranslationFields/TranslationFieldsRich.tsx +++ b/src/translations/components/TranslationFields/TranslationFieldsRich.tsx @@ -1,11 +1,11 @@ import Typography from "@material-ui/core/Typography"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import DraftRenderer from "@saleor/components/DraftRenderer"; import Form from "@saleor/components/Form"; import RichTextEditor from "@saleor/components/RichTextEditor"; -import i18n from "../../../i18n"; import TranslationFieldsSave from "./TranslationFieldsSave"; interface TranslationFieldsRichProps { @@ -24,8 +24,10 @@ const TranslationFieldsRich: React.FC = ({ saveButtonState, onDiscard, onSubmit -}) => - edit ? ( +}) => { + const intl = useIntl(); + + return edit ? (
    onSubmit(data.translation)} @@ -37,7 +39,9 @@ const TranslationFieldsRich: React.FC = ({ error={undefined} helperText={undefined} initial={JSON.parse(initial)} - label={i18n.t("Translation")} + label={intl.formatMessage({ + defaultMessage: "Translation" + })} name="translation" onChange={change} /> @@ -51,12 +55,13 @@ const TranslationFieldsRich: React.FC = ({ ) : initial === null ? ( - {i18n.t("No translation yet")} + ) : ( ); +}; TranslationFieldsRich.displayName = "TranslationFieldsRich"; export default TranslationFieldsRich; diff --git a/src/translations/components/TranslationFields/TranslationFieldsSave.tsx b/src/translations/components/TranslationFields/TranslationFieldsSave.tsx index 364aace74..fdf6cadab 100644 --- a/src/translations/components/TranslationFields/TranslationFieldsSave.tsx +++ b/src/translations/components/TranslationFields/TranslationFieldsSave.tsx @@ -6,11 +6,12 @@ import { WithStyles } from "@material-ui/core/styles"; import React from "react"; +import { FormattedMessage } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import i18n from "../../../i18n"; +import { buttonMessages } from "@saleor/intl"; interface TranslationFieldsSaveProps { saveButtonState: ConfirmButtonTransitionState; @@ -45,9 +46,11 @@ const TranslationFieldsSave = withStyles(styles, { transitionState={saveButtonState} onClick={onSave} > - {i18n.t("Save")} + - +
    ) ); diff --git a/src/translations/components/TranslationFields/TranslationFieldsShort.tsx b/src/translations/components/TranslationFields/TranslationFieldsShort.tsx index df689dfb4..2d02261ac 100644 --- a/src/translations/components/TranslationFields/TranslationFieldsShort.tsx +++ b/src/translations/components/TranslationFields/TranslationFieldsShort.tsx @@ -1,10 +1,10 @@ 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 { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; -import i18n from "../../../i18n"; import TranslationFieldsSave from "./TranslationFieldsSave"; interface TranslationFieldsShortProps { @@ -23,8 +23,10 @@ const TranslationFieldsShort: React.FC = ({ saveButtonState, onDiscard, onSubmit -}) => - edit ? ( +}) => { + const intl = useIntl(); + + return edit ? (
    onSubmit(data.translation)} @@ -34,7 +36,9 @@ const TranslationFieldsShort: React.FC = ({ = ({ ) : initial === null ? ( - {i18n.t("No translation yet")} + ) : ( {initial} ); +}; TranslationFieldsShort.displayName = "TranslationFieldsShort"; export default TranslationFieldsShort; diff --git a/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.tsx b/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.tsx index 37a595bbb..db944aa30 100644 --- a/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.tsx +++ b/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.tsx @@ -1,11 +1,12 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { CategoryTranslationFragment } from "../../types/CategoryTranslationFragment"; @@ -38,87 +39,103 @@ const TranslationsCategoriesPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - category.name, "..."), - context: "category translation page title", - languageCode - } - )} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + category.name, "..."), + languageCode + } + )} + > + + + + category.translation ? category.translation.name : null + ), + type: "short" as "short", + value: maybe(() => category.name) + }, + { + displayName: intl.formatMessage(commonMessages.description), + name: fieldNames.descriptionJson, + translation: maybe(() => + category.translation ? category.translation.descriptionJson : null + ), + type: "rich" as "rich", + value: maybe(() => category.descriptionJson) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} /> - - - category.translation ? category.translation.name : null - ), - type: "short" as "short", - value: maybe(() => category.name) - }, - { - displayName: i18n.t("Description"), - name: fieldNames.descriptionJson, - translation: maybe(() => - category.translation ? category.translation.descriptionJson : null - ), - type: "rich" as "rich", - value: maybe(() => category.descriptionJson) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - - - category.translation ? category.translation.seoTitle : null - ), - type: "short" as "short", - value: maybe(() => category.seoTitle) - }, - { - displayName: i18n.t("Search Engine Description"), - name: fieldNames.seoDescription, - translation: maybe(() => - category.translation ? category.translation.seoDescription : null - ), - type: "long" as "long", - value: maybe(() => category.seoDescription) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - -); + + + category.translation ? category.translation.seoTitle : null + ), + type: "short" as "short", + value: maybe(() => category.seoTitle) + }, + { + displayName: intl.formatMessage({ + defaultMessage: "Search Engine Description" + }), + name: fieldNames.seoDescription, + translation: maybe(() => + category.translation ? category.translation.seoDescription : null + ), + type: "long" as "long", + value: maybe(() => category.seoDescription) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} + /> +
    + ); +}; TranslationsCategoriesPage.displayName = "TranslationsCategoriesPage"; export default TranslationsCategoriesPage; diff --git a/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.tsx b/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.tsx index aeca74ee2..9f1b84da3 100644 --- a/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.tsx +++ b/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.tsx @@ -1,11 +1,12 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { CollectionTranslationFragment } from "../../types/CollectionTranslationFragment"; @@ -38,91 +39,108 @@ const TranslationsCollectionsPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - collection.name, "..."), - context: "collection translation page title", - languageCode - } - )} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + collection.name, "..."), + languageCode + } + )} + > + + + + collection.translation ? collection.translation.name : null + ), + type: "short" as "short", + value: maybe(() => collection.name) + }, + { + displayName: intl.formatMessage(commonMessages.description), + name: fieldNames.descriptionJson, + translation: maybe(() => + collection.translation + ? collection.translation.descriptionJson + : null + ), + type: "rich" as "rich", + value: maybe(() => collection.descriptionJson) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} /> - - - collection.translation ? collection.translation.name : null - ), - type: "short" as "short", - value: maybe(() => collection.name) - }, - { - displayName: i18n.t("Description"), - name: fieldNames.descriptionJson, - translation: maybe(() => - collection.translation - ? collection.translation.descriptionJson - : null - ), - type: "rich" as "rich", - value: maybe(() => collection.descriptionJson) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - - - collection.translation ? collection.translation.seoTitle : null - ), - type: "short" as "short", - value: maybe(() => collection.seoTitle) - }, - { - displayName: i18n.t("Search Engine Description"), - name: fieldNames.seoDescription, - translation: maybe(() => - collection.translation - ? collection.translation.seoDescription - : null - ), - type: "long" as "long", - value: maybe(() => collection.seoDescription) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - -); + + + collection.translation ? collection.translation.seoTitle : null + ), + type: "short" as "short", + value: maybe(() => collection.seoTitle) + }, + { + displayName: intl.formatMessage({ + defaultMessage: "Search Engine Description" + }), + name: fieldNames.seoDescription, + translation: maybe(() => + collection.translation + ? collection.translation.seoDescription + : null + ), + type: "long" as "long", + value: maybe(() => collection.seoDescription) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} + /> + + ); +}; TranslationsCollectionsPage.displayName = "TranslationsCollectionsPage"; export default TranslationsCollectionsPage; diff --git a/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.tsx b/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.tsx index 161355735..a3d36cf71 100644 --- a/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.tsx +++ b/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.tsx @@ -8,11 +8,12 @@ import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import classNames from "classnames"; import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + import { ListProps } from "../../../types"; import Skeleton from "@saleor/components/Skeleton"; import TablePagination from "@saleor/components/TablePagination"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; export interface TranslatableEntity { @@ -52,73 +53,81 @@ const TranslationsEntitiesList = withStyles(styles, { onPreviousPage, onRowClick, pageInfo - }: TranslationsEntitiesListProps & WithStyles) => ( - - - - - {i18n.t("Name", { context: "table header" })} - - - {i18n.t("Completed Translations", { - context: "table header" - })} - - - - - - - - - - {renderCollection( - entities, - entity => ( - onRowClick(entity.id) : undefined} - key={entity ? entity.id : "skeleton"} - > - - {maybe(() => entity.name, )} - - - {maybe( - () => - i18n.t("{{ current }} of {{ max }}", { - context: "translation progress", - ...entity.completion - }), - - )} - - - ), - () => ( - - - {i18n.t("No translatable entities found")} - - - ) - )} - -
    - ) + }: TranslationsEntitiesListProps & WithStyles) => { + const intl = useIntl(); + + return ( + + + + + + + + + + + + + + + + + + {renderCollection( + entities, + entity => ( + onRowClick(entity.id) : undefined} + key={entity ? entity.id : "skeleton"} + > + + {maybe(() => entity.name, )} + + + {maybe( + () => + intl.formatMessage( + { + defaultMessage: "{current} of {max}", + description: "translation progress" + }, + entity.completion + ), + + )} + + + ), + () => ( + + + + + + ) + )} + +
    + ); + } ); TranslationsEntitiesList.displayName = "TranslationsEntitiesList"; export default TranslationsEntitiesList; diff --git a/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.tsx b/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.tsx index 8af4b7940..cf76b23c5 100644 --- a/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.tsx +++ b/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.tsx @@ -1,5 +1,6 @@ import Card from "@material-ui/core/Card"; import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; @@ -7,8 +8,7 @@ import PageHeader from "@saleor/components/PageHeader"; // tslint:disable no-submodule-imports import { ShopInfo_shop_languages } from "@saleor/components/Shop/types/ShopInfo"; import FilterTabs, { FilterTab } from "@saleor/components/TableFilter"; -import i18n from "../../../i18n"; -import { maybe } from "../../../misc"; +import { maybe } from "@saleor/misc"; import { TranslatableEntities } from "../../urls"; export interface TranslationsEntitiesListPageProps { @@ -33,53 +33,86 @@ export type TranslationsEntitiesListFilterTab = keyof typeof TranslatableEntitie const TranslationsEntitiesListPage: React.StatelessComponent< TranslationsEntitiesListPageProps -> = ({ filters, language, onBack, children }) => ( - - {i18n.t("Languages")} - language.language, "...") - })} - /> - - - - - - - - - - - {children} - - -); +> = ({ filters, language, onBack, children }) => { + const intl = useIntl(); + + return ( + + + {intl.formatMessage({ + defaultMessage: "Languages" + })} + + language.language, "...") + } + )} + /> + + + + + + + + + + + {children} + + + ); +}; TranslationsEntitiesListPage.displayName = "TranslationsEntitiesListPage"; export default TranslationsEntitiesListPage; diff --git a/src/translations/components/TranslationsLanguageList/TranslationsLanguageList.tsx b/src/translations/components/TranslationsLanguageList/TranslationsLanguageList.tsx index 6ccceb449..8412811e2 100644 --- a/src/translations/components/TranslationsLanguageList/TranslationsLanguageList.tsx +++ b/src/translations/components/TranslationsLanguageList/TranslationsLanguageList.tsx @@ -6,11 +6,11 @@ import TableCell from "@material-ui/core/TableCell"; import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import React from "react"; +import { FormattedMessage } from "react-intl"; // tslint:disable no-submodule-imports import { ShopInfo_shop_languages } from "@saleor/components/Shop/types/ShopInfo"; import Skeleton from "@saleor/components/Skeleton"; -import i18n from "../../../i18n"; import { maybe, renderCollection } from "../../../misc"; export interface TranslationsLanguageListProps { @@ -40,7 +40,7 @@ const TranslationsLanguageList = withStyles(styles, { - {i18n.t("Language", { context: "table header" })} + @@ -65,7 +65,7 @@ const TranslationsLanguageList = withStyles(styles, { () => ( - {i18n.t("No languages found")} + ) diff --git a/src/translations/components/TranslationsLanguageListPage/TranslationsLanguageListPage.tsx b/src/translations/components/TranslationsLanguageListPage/TranslationsLanguageListPage.tsx index d46a95d08..e78ecc426 100644 --- a/src/translations/components/TranslationsLanguageListPage/TranslationsLanguageListPage.tsx +++ b/src/translations/components/TranslationsLanguageListPage/TranslationsLanguageListPage.tsx @@ -1,12 +1,12 @@ // import Button from "@material-ui/core/Button"; // import AddIcon from "@material-ui/icons/Add"; import React from "react"; +import { useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; // tslint:disable no-submodule-imports import { ShopInfo_shop_languages } from "@saleor/components/Shop/types/ShopInfo"; -import i18n from "../../../i18n"; import TranslationsLanguageList from "../TranslationsLanguageList"; export interface TranslationsLanguageListPageProps { @@ -17,16 +17,27 @@ export interface TranslationsLanguageListPageProps { const TranslationsLanguageListPage: React.StatelessComponent< TranslationsLanguageListPageProps -> = ({ languages, onRowClick }) => ( - - - {/* */} - - - -); + + + + ); +}; TranslationsLanguageListPage.displayName = "TranslationsLanguageListPage"; export default TranslationsLanguageListPage; diff --git a/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.tsx b/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.tsx index ff2df9c3f..88e3ec0a3 100644 --- a/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.tsx +++ b/src/translations/components/TranslationsPagesPage/TranslationsPagesPage.tsx @@ -1,11 +1,12 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { PageTranslationFragment } from "../../types/PageTranslationFragment"; @@ -38,84 +39,106 @@ const TranslationsPagesPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - page.title, "...") - })} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + page.title, "...") + } + )} + > + + + + page.translation ? page.translation.title : null + ), + type: "short" as "short", + value: maybe(() => page.title) + }, + { + displayName: intl.formatMessage({ + defaultMessage: "Content", + description: "page content" + }), + name: fieldNames.contentJson, + translation: maybe(() => + page.translation ? page.translation.contentJson : null + ), + type: "rich" as "rich", + value: maybe(() => page.contentJson) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} /> - - - page.translation ? page.translation.title : null - ), - type: "short" as "short", - value: maybe(() => page.title) - }, - { - displayName: i18n.t("Content"), - name: fieldNames.contentJson, - translation: maybe(() => - page.translation ? page.translation.contentJson : null - ), - type: "rich" as "rich", - value: maybe(() => page.contentJson) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - - - page.translation ? page.translation.seoTitle : null - ), - type: "short" as "short", - value: maybe(() => page.seoTitle) - }, - { - displayName: i18n.t("Search Engine Description"), - name: fieldNames.seoDescription, - translation: maybe(() => - page.translation ? page.translation.seoDescription : null - ), - type: "long" as "long", - value: maybe(() => page.seoDescription) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - -); + + + page.translation ? page.translation.seoTitle : null + ), + type: "short" as "short", + value: maybe(() => page.seoTitle) + }, + { + displayName: intl.formatMessage({ + defaultMessage: "Search Engine Description" + }), + name: fieldNames.seoDescription, + translation: maybe(() => + page.translation ? page.translation.seoDescription : null + ), + type: "long" as "long", + value: maybe(() => page.seoDescription) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} + /> + + ); +}; TranslationsPagesPage.displayName = "TranslationsPagesPage"; export default TranslationsPagesPage; diff --git a/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.tsx b/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.tsx index 0caed56bd..746bc4b44 100644 --- a/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.tsx +++ b/src/translations/components/TranslationsProductTypesPage/TranslationsProductTypesPage.tsx @@ -1,11 +1,12 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { ProductTypeTranslationFragment } from "../../types/ProductTypeTranslationFragment"; @@ -36,125 +37,164 @@ const TranslationsProductTypesPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - productType.name, "...") - } - )} - > - - - {maybe(() => productType.productAttributes, []).map( - (attribute, attributeIndex) => ( - <> - - attribute.translation ? attribute.translation.name : null - ), - type: "short" as "short", - value: maybe(() => attribute.name) - }, - ...attribute.values.map( - (attributeValue, attributeValueIndex) => ({ - displayName: i18n.t("Value {{ number }}", { - number: attributeValueIndex + 1 +}) => { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + productType.name, "...") + } + )} + > + + + {maybe(() => productType.productAttributes, []).map( + (attribute, attributeIndex) => ( + <> + - attributeValue.translation - ? attributeValue.translation.name - : null + attribute.translation ? attribute.translation.name : null ), type: "short" as "short", - value: maybe(() => attributeValue.name) - }) - ) - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - {attributeIndex < productType.productAttributes.length - 1 && ( - - )} - - ) - )} - { - <> - - {maybe(() => productType.variantAttributes, []).map( - (attribute, attributeIndex) => ( - <> - attribute.name) + }, + ...attribute.values.map( + (attributeValue, attributeValueIndex) => ({ + displayName: intl.formatMessage( + { + defaultMessage: "Value {number}", + description: "attribute values" + }, + { + number: attributeValueIndex + 1 + } + ), + name: fieldNames.value + ":" + attributeValue.id, translation: maybe(() => - attribute.translation ? attribute.translation.name : null + attributeValue.translation + ? attributeValue.translation.name + : null ), type: "short" as "short", - value: maybe(() => attribute.name) - }, - ...attribute.values.map( - (attributeValue, attributeValueIndex) => ({ - displayName: i18n.t("Value {{ number }}", { - number: attributeValueIndex + 1 + value: maybe(() => attributeValue.name) + }) + ) + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} + /> + {attributeIndex < productType.productAttributes.length - 1 && ( + + )} + + ) + )} + { + <> + + {maybe(() => productType.variantAttributes, []).map( + (attribute, attributeIndex) => ( + <> + - attributeValue.translation - ? attributeValue.translation.name + attribute.translation + ? attribute.translation.name : null ), type: "short" as "short", - value: maybe(() => attributeValue.name) - }) - ) - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - {attributeIndex < productType.variantAttributes.length - 1 && ( - - )} - - ) - )} - - } - -); + value: maybe(() => attribute.name) + }, + ...attribute.values.map( + (attributeValue, attributeValueIndex) => ({ + displayName: intl.formatMessage( + { + defaultMessage: "Value {number}", + description: "attribute values" + }, + { + number: attributeValueIndex + 1 + } + ), + name: fieldNames.value + ":" + attributeValue.id, + translation: maybe(() => + attributeValue.translation + ? attributeValue.translation.name + : null + ), + type: "short" as "short", + value: maybe(() => attributeValue.name) + }) + ) + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} + /> + {attributeIndex < productType.variantAttributes.length - 1 && ( + + )} + + ) + )} + + } + + ); +}; TranslationsProductTypesPage.displayName = "TranslationsProductTypesPage"; export default TranslationsProductTypesPage; diff --git a/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.tsx b/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.tsx index f8b797e71..40b52c1bc 100644 --- a/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.tsx +++ b/src/translations/components/TranslationsProductsPage/TranslationsProductsPage.tsx @@ -1,11 +1,12 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import CardSpacer from "@saleor/components/CardSpacer"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { ProductTranslationFragment } from "../../types/ProductTranslationFragment"; @@ -38,87 +39,106 @@ const TranslationsProductsPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - product.name, "...") - } - )} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + product.name, "...") + } + )} + > + + + + product.translation ? product.translation.name : null + ), + type: "short" as "short", + value: maybe(() => product.name) + }, + { + displayName: intl.formatMessage({ + defaultMessage: "Description" + }), + name: fieldNames.descriptionJson, + translation: maybe(() => + product.translation ? product.translation.descriptionJson : null + ), + type: "rich" as "rich", + value: maybe(() => product.descriptionJson) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} /> - - - product.translation ? product.translation.name : null - ), - type: "short" as "short", - value: maybe(() => product.name) - }, - { - displayName: i18n.t("Description"), - name: fieldNames.descriptionJson, - translation: maybe(() => - product.translation ? product.translation.descriptionJson : null - ), - type: "rich" as "rich", - value: maybe(() => product.descriptionJson) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - - - product.translation ? product.translation.seoTitle : null - ), - type: "short" as "short", - value: maybe(() => product.seoTitle) - }, - { - displayName: i18n.t("Search Engine Description"), - name: fieldNames.seoDescription, - translation: maybe(() => - product.translation ? product.translation.seoDescription : null - ), - type: "long" as "long", - value: maybe(() => product.seoDescription) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - -); + + + product.translation ? product.translation.seoTitle : null + ), + type: "short" as "short", + value: maybe(() => product.seoTitle) + }, + { + displayName: intl.formatMessage({ + defaultMessage: "Search Engine Description" + }), + name: fieldNames.seoDescription, + translation: maybe(() => + product.translation ? product.translation.seoDescription : null + ), + type: "long" as "long", + value: maybe(() => product.seoDescription) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} + /> + + ); +}; TranslationsProductsPage.displayName = "TranslationsProductsPage"; export default TranslationsProductsPage; diff --git a/src/translations/components/TranslationsSalesPage/TranslationsSalesPage.tsx b/src/translations/components/TranslationsSalesPage/TranslationsSalesPage.tsx index 55f4e32bd..12f590351 100644 --- a/src/translations/components/TranslationsSalesPage/TranslationsSalesPage.tsx +++ b/src/translations/components/TranslationsSalesPage/TranslationsSalesPage.tsx @@ -1,10 +1,11 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { SaleTranslationFragment } from "../../types/SaleTranslationFragment"; @@ -34,44 +35,57 @@ const TranslationsSalesPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - sale.name, "...") - })} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + sale.name, "...") + } + )} + > + + + + sale.translation ? sale.translation.name : null + ), + type: "short" as "short", + value: maybe(() => sale.name) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} /> - - - sale.translation ? sale.translation.name : null - ), - type: "short" as "short", - value: maybe(() => sale.name) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - -); + + ); +}; TranslationsSalesPage.displayName = "TranslationsSalesPage"; export default TranslationsSalesPage; diff --git a/src/translations/components/TranslationsVouchersPage/TranslationsVouchersPage.tsx b/src/translations/components/TranslationsVouchersPage/TranslationsVouchersPage.tsx index 2bab4dcef..a7a68be07 100644 --- a/src/translations/components/TranslationsVouchersPage/TranslationsVouchersPage.tsx +++ b/src/translations/components/TranslationsVouchersPage/TranslationsVouchersPage.tsx @@ -1,10 +1,11 @@ import React from "react"; +import { useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import LanguageSwitch from "@saleor/components/LanguageSwitch"; import PageHeader from "@saleor/components/PageHeader"; -import i18n from "../../../i18n"; +import { commonMessages, sectionNames } from "@saleor/intl"; import { maybe } from "../../../misc"; import { LanguageCodeEnum } from "../../../types/globalTypes"; import { TranslationsEntitiesPageProps } from "../../types/TranslationsEntitiesPage"; @@ -34,47 +35,58 @@ const TranslationsVouchersPage: React.StatelessComponent< onEdit, onLanguageChange, onSubmit -}) => ( - - {i18n.t("Translations")} - voucher.name, "...") - } - )} - > - { + const intl = useIntl(); + + return ( + + + {intl.formatMessage(sectionNames.translations)} + + voucher.name, "...") + } + )} + > + + + + voucher.translation ? voucher.translation.name : null + ), + type: "short" as "short", + value: maybe(() => voucher.name) + } + ]} + saveButtonState={saveButtonState} + onEdit={onEdit} + onDiscard={onDiscard} + onSubmit={onSubmit} /> - - - voucher.translation ? voucher.translation.name : null - ), - type: "short" as "short", - value: maybe(() => voucher.name) - } - ]} - saveButtonState={saveButtonState} - onEdit={onEdit} - onDiscard={onDiscard} - onSubmit={onSubmit} - /> - -); + + ); +}; TranslationsVouchersPage.displayName = "TranslationsVouchersPage"; export default TranslationsVouchersPage; diff --git a/src/translations/index.tsx b/src/translations/index.tsx index 92ae9b2b2..b6d05f925 100644 --- a/src/translations/index.tsx +++ b/src/translations/index.tsx @@ -1,9 +1,10 @@ import { parse as parseQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import { Route, RouteComponentProps, Switch } from "react-router-dom"; +import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; -import i18n from "../i18n"; import { LanguageCodeEnum } from "../types/globalTypes"; import { languageEntitiesPath, @@ -174,85 +175,89 @@ const TranslationsProductTypes: React.FC = ({ ); }; -const TranslationsRouter: React.FC = () => ( - <> - - - - - - - - - - - - - -); +const TranslationsRouter: React.FC = () => { + const intl = useIntl(); + + return ( + <> + + + + + + + + + + + + + + ); +}; TranslationsRouter.displayName = "TranslationsRouter"; export default TranslationsRouter; diff --git a/src/translations/views/TranslationsCategories.tsx b/src/translations/views/TranslationsCategories.tsx index d3e9961a4..57bbb82b6 100644 --- a/src/translations/views/TranslationsCategories.tsx +++ b/src/translations/views/TranslationsCategories.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, TranslationInput } from "../../types/globalTypes"; import TranslationsCategoriesPage, { @@ -36,6 +37,7 @@ const TranslationsCategories: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -48,7 +50,7 @@ const TranslationsCategories: React.FC = ({ const onUpdate = (data: UpdateCategoryTranslations) => { if (data.categoryTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/translations/views/TranslationsCollections.tsx b/src/translations/views/TranslationsCollections.tsx index d213aa5af..1dd5c68ad 100644 --- a/src/translations/views/TranslationsCollections.tsx +++ b/src/translations/views/TranslationsCollections.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, TranslationInput } from "../../types/globalTypes"; import TranslationsCollectionsPage, { @@ -36,6 +37,7 @@ const TranslationsCollections: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -48,7 +50,7 @@ const TranslationsCollections: React.FC = ({ const onUpdate = (data: UpdateCollectionTranslations) => { if (data.collectionTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/translations/views/TranslationsPages.tsx b/src/translations/views/TranslationsPages.tsx index 337070582..6cffea703 100644 --- a/src/translations/views/TranslationsPages.tsx +++ b/src/translations/views/TranslationsPages.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, @@ -39,6 +40,7 @@ const TranslationsPages: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -51,7 +53,7 @@ const TranslationsPages: React.FC = ({ const onUpdate = (data: UpdatePageTranslations) => { if (data.pageTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/translations/views/TranslationsProductTypes.tsx b/src/translations/views/TranslationsProductTypes.tsx index af769063b..02a1b8599 100644 --- a/src/translations/views/TranslationsProductTypes.tsx +++ b/src/translations/views/TranslationsProductTypes.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, @@ -43,6 +44,7 @@ const TranslationsProductTypes: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -55,7 +57,7 @@ const TranslationsProductTypes: React.FC = ({ const onAttributeUpdate = (data: UpdateAttributeTranslations) => { if (data.attributeTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } @@ -63,7 +65,7 @@ const TranslationsProductTypes: React.FC = ({ const onAttributeValueUpdate = (data: UpdateAttributeValueTranslations) => { if (data.attributeValueTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/translations/views/TranslationsProducts.tsx b/src/translations/views/TranslationsProducts.tsx index f6dbefb3b..b343cc87b 100644 --- a/src/translations/views/TranslationsProducts.tsx +++ b/src/translations/views/TranslationsProducts.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, TranslationInput } from "../../types/globalTypes"; import TranslationsProductsPage, { @@ -36,6 +37,7 @@ const TranslationsProducts: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -48,7 +50,7 @@ const TranslationsProducts: React.FC = ({ const onUpdate = (data: UpdateProductTranslations) => { if (data.productTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/translations/views/TranslationsSales.tsx b/src/translations/views/TranslationsSales.tsx index 967d7a4a0..942e044c5 100644 --- a/src/translations/views/TranslationsSales.tsx +++ b/src/translations/views/TranslationsSales.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, @@ -39,6 +40,7 @@ const TranslationsSales: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -51,7 +53,7 @@ const TranslationsSales: React.FC = ({ const onUpdate = (data: UpdateSaleTranslations) => { if (data.saleTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/translations/views/TranslationsVouchers.tsx b/src/translations/views/TranslationsVouchers.tsx index d30f4e3d4..4deb1e366 100644 --- a/src/translations/views/TranslationsVouchers.tsx +++ b/src/translations/views/TranslationsVouchers.tsx @@ -1,10 +1,11 @@ import { stringify as stringifyQs } from "qs"; import React from "react"; +import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; -import i18n from "../../i18n"; +import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "../../misc"; import { LanguageCodeEnum, @@ -39,6 +40,7 @@ const TranslationsVouchers: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); + const intl = useIntl(); const onEdit = (field: string) => navigate( @@ -51,7 +53,7 @@ const TranslationsVouchers: React.FC = ({ const onUpdate = (data: UpdateVoucherTranslations) => { if (data.voucherTranslate.errors.length === 0) { notify({ - text: i18n.t("Translation Saved") + text: intl.formatMessage(commonMessages.savedChanges) }); navigate("?", true); } diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts deleted file mode 100644 index 2781c0056..000000000 --- a/src/utils/i18n.ts +++ /dev/null @@ -1,5 +0,0 @@ -import i18n from "@saleor/i18n"; - -export function translateBoolean(value: boolean): string { - return value ? i18n.t("Yes") : i18n.t("No"); -} diff --git a/tsconfig.json b/tsconfig.json index 0962d2367..c0f25c825 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "paths": { "@assets/*": ["assets/*"], "@saleor/*": ["src/*"] - } + }, + "resolveJsonModule": true }, "exclude": ["node_modules"] } diff --git a/webpack.config.js b/webpack.config.js index c49817f26..55c8ce335 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -66,17 +66,11 @@ module.exports = (env, argv) => { module: { rules: [ { - test: /\.jsx?$/, + test: /\.(jsx?|tsx?)$/, exclude: /node_modules/, - loader: "babel-loader" - }, - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "ts-loader", + loader: "babel-loader", options: { - experimentalWatchApi: true, - transpileOnly: true + configFile: resolve("./babel.config.js") } }, {