@salesforce/retail-react-app 2.2.0-preview.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/app/components/_error/index.test.js +8 -5
- package/app/components/icons/index.jsx +25 -4
- package/app/components/icons/index.test.js +38 -0
- package/app/components/list-menu/index.jsx +12 -12
- package/app/components/promo-popover/index.jsx +0 -1
- package/app/pages/cart/partials/cart-secondary-button-group.jsx +0 -1
- package/app/pages/home/index.jsx +8 -9
- package/app/static/translations/compiled/en-GB.json +7 -1
- package/package.json +8 -8
- package/scripts/translations/extract-default-messages.js +32 -41
- package/translations/en-GB.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
## v2.2.0
|
|
1
|
+
## v2.2.0 (Nov 8, 2023)
|
|
2
2
|
|
|
3
3
|
### Accessibility Improvements
|
|
4
4
|
|
|
5
5
|
<!-- Order by Pull Request ID! -->
|
|
6
|
+
- Ensure the ListMenuTrigger component applies ARIA attributes to the correct element for the trigger icon [#1600](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1600)
|
|
6
7
|
- Ensure form fields and icons have accessible labels [#1526](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1526)
|
|
7
8
|
- Ensure active user interface components have sufficient contrast [#1534](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1534)
|
|
8
9
|
- Fix outline on keyboard focus [#1536](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1536/files)
|
|
@@ -11,6 +12,7 @@
|
|
|
11
12
|
- Make security code tooltip receive keyboard focus [#1551](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1551)
|
|
12
13
|
- Improve accessibility of quantity picker [#1552](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1552)
|
|
13
14
|
- Improve keyboard accessibility of product scroller [#1559](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1559)
|
|
15
|
+
- Fix focus indicator for hero features links on homepage [#1561](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1561)
|
|
14
16
|
- Ensure color is not the sole means of communicating information [#1570](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1570)
|
|
15
17
|
|
|
16
18
|
### Other Features
|
|
@@ -18,11 +20,15 @@
|
|
|
18
20
|
- Add [Active Data](https://help.salesforce.com/s/articleView?id=cc.b2c_active_data_attributes.htm&type=5) files, update pages (app index.jsx, product list and product details pages) to trigger events on product category and product detail views [#1555](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1555)
|
|
19
21
|
- Replace max-age with s-maxage to only cache shared caches [#1564](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1564)
|
|
20
22
|
- Implement gift option for basket [#1546](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1546)
|
|
23
|
+
- Update `extract-default-messages` script to support multiple locales [#1574](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1574)
|
|
24
|
+
- Update engine compatibility to include npm 10 [#1597](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1597)
|
|
25
|
+
- Add support for localization in icon component [#1609](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1609)
|
|
21
26
|
|
|
22
27
|
### Bug Fixes
|
|
23
28
|
|
|
24
29
|
- Remove internal linter rule that is missing in generated projects [#1554](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1554)
|
|
25
30
|
- Fix bug where you can add duplicates of the same item to the wishlist. Also fixes bug where skeleton appears when removing last item from the wishlist. [#1560](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1560)
|
|
31
|
+
- Replace max-age with s-maxage to only cache shared caches [#1564](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1564)
|
|
26
32
|
- Fix PLP filters for mobile [#1565](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1565)
|
|
27
33
|
|
|
28
34
|
## v2.1.1 (Nov 7, 2023)
|
|
@@ -5,21 +5,24 @@
|
|
|
5
5
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react'
|
|
8
|
-
import {screen} from '@testing-library/react'
|
|
9
|
-
import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
|
|
10
8
|
import Error from '@salesforce/retail-react-app/app/components/_error/index'
|
|
9
|
+
// !!! ----- WARNING ----- WARNING ----- WARNING ----- !!!
|
|
10
|
+
// Tests use render instead of renderWithProviders because
|
|
11
|
+
// error component is rendered outside provider tree
|
|
12
|
+
// !!! ----------------------------------------------- !!!
|
|
13
|
+
import {screen, render} from '@testing-library/react'
|
|
11
14
|
|
|
12
15
|
test('Error renders without errors', () => {
|
|
13
|
-
expect(
|
|
16
|
+
expect(render(<Error />)).toBeDefined()
|
|
14
17
|
})
|
|
15
18
|
|
|
16
19
|
test('Error status 500', () => {
|
|
17
|
-
|
|
20
|
+
render(<Error status={500} />)
|
|
18
21
|
expect(screen.getByRole('heading', {level: 2})).toHaveTextContent("This page isn't working")
|
|
19
22
|
})
|
|
20
23
|
|
|
21
24
|
test('Error status 500 with stack trace', () => {
|
|
22
|
-
|
|
25
|
+
render(<Error status={500} stack={'Stack trace error message'} />)
|
|
23
26
|
expect(screen.getByRole('heading', {level: 2})).toHaveTextContent("This page isn't working")
|
|
24
27
|
expect(screen.getByText(/stack trace error message/i)).toBeInTheDocument()
|
|
25
28
|
})
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
5
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
6
|
*/
|
|
7
|
-
import React, {forwardRef} from 'react'
|
|
8
|
-
import {
|
|
7
|
+
import React, {forwardRef, useContext} from 'react'
|
|
8
|
+
import {defineMessage, IntlContext} from 'react-intl'
|
|
9
|
+
import PropTypes from 'prop-types'
|
|
9
10
|
import {Icon, useTheme} from '@salesforce/retail-react-app/app/components/shared/ui'
|
|
10
11
|
|
|
11
12
|
// Our own SVG imports. These will be extracted to a single sprite sheet by the
|
|
@@ -85,7 +86,9 @@ VisaSymbol.viewBox = VisaSymbol.viewBox || '0 0 38 22'
|
|
|
85
86
|
* @param {string} name - the filename of the imported svg (does not include extension)
|
|
86
87
|
* @param {Object} passProps - props that will be passed onto the underlying Icon component
|
|
87
88
|
* @param {Object} localizationAttributes - attributes with localized values that will be passed
|
|
88
|
-
* onto the underlying Icon component, use `defineMessage` to create localized string
|
|
89
|
+
* onto the underlying Icon component, use `defineMessage` to create localized string.
|
|
90
|
+
* Additionally, if the icon is rendered outside the provider tree, you'll also need to
|
|
91
|
+
* pass an intl object from react-intl as a prop to translate the messages.
|
|
89
92
|
*/
|
|
90
93
|
/* istanbul ignore next */
|
|
91
94
|
export const icon = (name, passProps, localizationAttributes) => {
|
|
@@ -95,8 +98,21 @@ export const icon = (name, passProps, localizationAttributes) => {
|
|
|
95
98
|
.replace(/-/g, '')
|
|
96
99
|
const component = forwardRef((props, ref) => {
|
|
97
100
|
const theme = useTheme()
|
|
98
|
-
|
|
101
|
+
// NOTE: We want to avoid `useIntl` here because that throws when <IntlProvider> is not in
|
|
102
|
+
// the component ancestry, but we only enforce `intl` if we have `localizationAttributes`.
|
|
103
|
+
let intl = useContext(IntlContext)
|
|
99
104
|
if (localizationAttributes) {
|
|
105
|
+
if (props?.intl) {
|
|
106
|
+
const {intl: intlProp, ...otherProps} = props
|
|
107
|
+
// Allow `props.intl` to take precedence over the intl we found
|
|
108
|
+
intl = intlProp
|
|
109
|
+
props = otherProps
|
|
110
|
+
}
|
|
111
|
+
if (!intl) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
'To localize messages, you must either have <IntlProvider> in the component ancestry or provide `intl` as a prop'
|
|
114
|
+
)
|
|
115
|
+
}
|
|
100
116
|
Object.keys(localizationAttributes).forEach((key) => {
|
|
101
117
|
passProps[key] = intl.formatMessage(localizationAttributes[key])
|
|
102
118
|
})
|
|
@@ -108,6 +124,11 @@ export const icon = (name, passProps, localizationAttributes) => {
|
|
|
108
124
|
</Icon>
|
|
109
125
|
)
|
|
110
126
|
})
|
|
127
|
+
|
|
128
|
+
component.propTypes = {
|
|
129
|
+
intl: PropTypes.object
|
|
130
|
+
}
|
|
131
|
+
|
|
111
132
|
component.displayName = `${displayName}Icon`
|
|
112
133
|
return component
|
|
113
134
|
}
|
|
@@ -5,10 +5,21 @@
|
|
|
5
5
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react'
|
|
8
|
+
import {useIntl} from 'react-intl'
|
|
8
9
|
import {within} from '@testing-library/dom'
|
|
10
|
+
import {render} from '@testing-library/react'
|
|
9
11
|
import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
|
|
10
12
|
import * as Icons from '@salesforce/retail-react-app/app/components/icons/index'
|
|
11
13
|
|
|
14
|
+
jest.mock('react-intl', () => ({
|
|
15
|
+
...jest.requireActual('react-intl'),
|
|
16
|
+
useIntl: jest.fn()
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
jest.clearAllMocks()
|
|
21
|
+
})
|
|
22
|
+
|
|
12
23
|
test('renders svg icons with Chakra Icon component', () => {
|
|
13
24
|
renderWithProviders(<Icons.CheckIcon />)
|
|
14
25
|
const svg = document.querySelector('.chakra-icon')
|
|
@@ -18,3 +29,30 @@ test('renders svg icons with Chakra Icon component', () => {
|
|
|
18
29
|
expect(svg).toHaveAttribute('viewBox', '0 0 24 24')
|
|
19
30
|
expect(use).toHaveAttribute('xlink:href', '#check')
|
|
20
31
|
})
|
|
32
|
+
|
|
33
|
+
test('uses intl from context when rendered with providers', () => {
|
|
34
|
+
renderWithProviders(<Icons.LockIcon />)
|
|
35
|
+
expect(useIntl).toHaveBeenCalled()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// the icon component can exist outside the provider tree via the error component
|
|
39
|
+
// therefore we cannot use the useIntl hook because the <IntlProvider> component
|
|
40
|
+
// will not exist in the component tree, so we pass the intl object as a prop
|
|
41
|
+
test('uses intl from props when rendered outside provider tree', () => {
|
|
42
|
+
const mockIntl = {
|
|
43
|
+
formatMessage: jest.fn()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// render without providers
|
|
47
|
+
render(<Icons.LockIcon intl={mockIntl} />)
|
|
48
|
+
|
|
49
|
+
expect(mockIntl.formatMessage).toHaveBeenCalled()
|
|
50
|
+
expect(useIntl).not.toHaveBeenCalled()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('throws error when rendered outside provider tree and no intl prop is passed', async () => {
|
|
54
|
+
const errorMsg =
|
|
55
|
+
'To localize messages, you must either have <IntlProvider> in the component ancestry or provide `intl` as a prop'
|
|
56
|
+
// render without providers
|
|
57
|
+
expect(() => render(<Icons.LockIcon />)).toThrow(errorMsg)
|
|
58
|
+
})
|
|
@@ -69,21 +69,21 @@ const ListMenuTrigger = ({item, name, isOpen, onOpen, onClose, hasItems}) => {
|
|
|
69
69
|
{name}
|
|
70
70
|
</Link>
|
|
71
71
|
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
<PopoverTrigger>
|
|
73
|
+
<Link
|
|
74
|
+
as={RouteLink}
|
|
75
|
+
to={'#'}
|
|
76
|
+
onMouseOver={onOpen}
|
|
77
|
+
onKeyDown={(e) => {
|
|
78
|
+
keyMap[e.key]?.(e)
|
|
79
|
+
}}
|
|
80
|
+
{...baseStyle.listMenuTriggerLinkIcon}
|
|
81
|
+
>
|
|
82
82
|
<Fade in={hasItems}>
|
|
83
83
|
<ChevronIconTrigger {...baseStyle.selectedButtonIcon} />
|
|
84
84
|
</Fade>
|
|
85
|
-
</
|
|
86
|
-
</
|
|
85
|
+
</Link>
|
|
86
|
+
</PopoverTrigger>
|
|
87
87
|
</Box>
|
|
88
88
|
)
|
|
89
89
|
}
|
package/app/pages/home/index.jsx
CHANGED
|
@@ -130,13 +130,12 @@ const Home = () => {
|
|
|
130
130
|
{heroFeatures.map((feature, index) => {
|
|
131
131
|
const featureMessage = feature.message
|
|
132
132
|
return (
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<Link target="_blank" href={feature.href}>
|
|
133
|
+
<Link key={index} target="_blank" href={feature.href}>
|
|
134
|
+
<Box
|
|
135
|
+
background={'white'}
|
|
136
|
+
boxShadow="0px 2px 2px rgba(0, 0, 0, 0.1)"
|
|
137
|
+
borderRadius={'4px'}
|
|
138
|
+
>
|
|
140
139
|
<HStack>
|
|
141
140
|
<Flex
|
|
142
141
|
paddingLeft={6}
|
|
@@ -150,8 +149,8 @@ const Home = () => {
|
|
|
150
149
|
{intl.formatMessage(featureMessage.title)}
|
|
151
150
|
</Text>
|
|
152
151
|
</HStack>
|
|
153
|
-
</
|
|
154
|
-
</
|
|
152
|
+
</Box>
|
|
153
|
+
</Link>
|
|
155
154
|
)
|
|
156
155
|
})}
|
|
157
156
|
</SimpleGrid>
|
|
@@ -1339,6 +1339,12 @@
|
|
|
1339
1339
|
"value": " added to wishlist"
|
|
1340
1340
|
}
|
|
1341
1341
|
],
|
|
1342
|
+
"global.info.already_in_wishlist": [
|
|
1343
|
+
{
|
|
1344
|
+
"type": 0,
|
|
1345
|
+
"value": "Item is already in wishlist"
|
|
1346
|
+
}
|
|
1347
|
+
],
|
|
1342
1348
|
"global.info.removed_from_wishlist": [
|
|
1343
1349
|
{
|
|
1344
1350
|
"type": 0,
|
|
@@ -2327,7 +2333,7 @@
|
|
|
2327
2333
|
"value": " to wishlist"
|
|
2328
2334
|
}
|
|
2329
2335
|
],
|
|
2330
|
-
"product_tile.assistive_msg.
|
|
2336
|
+
"product_tile.assistive_msg.remove_from_wishlist": [
|
|
2331
2337
|
{
|
|
2332
2338
|
"type": 0,
|
|
2333
2339
|
"value": "Remove "
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/retail-react-app",
|
|
3
|
-
"version": "2.2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"license": "See license in LICENSE",
|
|
5
5
|
"author": "cc-pwa-kit@salesforce.com",
|
|
6
6
|
"ccExtensibility": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build-translations": "npm run extract-default-translations && npm run compile-translations && npm run compile-translations:pseudo",
|
|
15
15
|
"compile-translations": "node ./scripts/translations/compile-folder.js translations",
|
|
16
16
|
"compile-translations:pseudo": "node ./scripts/translations/compile-pseudo.js translations/en-US.json",
|
|
17
|
-
"extract-default-translations": "node ./scripts/translations/extract-default-messages.js en-US",
|
|
17
|
+
"extract-default-translations": "node ./scripts/translations/extract-default-messages.js en-US en-GB",
|
|
18
18
|
"format": "pwa-kit-dev format \"**/*.{js,jsx}\"",
|
|
19
19
|
"lint": "pwa-kit-dev lint \"**/*.{js,jsx}\"",
|
|
20
20
|
"lint:fix": "npm run lint -- --fix",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"@lhci/cli": "^0.11.0",
|
|
46
46
|
"@loadable/component": "^5.15.3",
|
|
47
47
|
"@peculiar/webcrypto": "^1.4.2",
|
|
48
|
-
"@salesforce/commerce-sdk-react": "1.2.0
|
|
49
|
-
"@salesforce/pwa-kit-dev": "3.3.0
|
|
50
|
-
"@salesforce/pwa-kit-react-sdk": "3.3.0
|
|
51
|
-
"@salesforce/pwa-kit-runtime": "3.3.0
|
|
48
|
+
"@salesforce/commerce-sdk-react": "1.2.0",
|
|
49
|
+
"@salesforce/pwa-kit-dev": "3.3.0",
|
|
50
|
+
"@salesforce/pwa-kit-react-sdk": "3.3.0",
|
|
51
|
+
"@salesforce/pwa-kit-runtime": "3.3.0",
|
|
52
52
|
"@tanstack/react-query": "^4.28.0",
|
|
53
53
|
"@tanstack/react-query-devtools": "^4.29.1",
|
|
54
54
|
"@testing-library/dom": "^9.0.1",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|
|
90
90
|
"node": "^16.11.0 || ^18.0.0",
|
|
91
|
-
"npm": "^8.0.0 || ^9.0.0"
|
|
91
|
+
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
|
|
92
92
|
},
|
|
93
93
|
"bundlesize": [
|
|
94
94
|
{
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"maxSize": "320 kB"
|
|
101
101
|
}
|
|
102
102
|
],
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "93894bb7d823f3510e10affdb1eb8e6750b25822"
|
|
104
104
|
}
|
|
@@ -16,77 +16,68 @@ const fs = require('fs')
|
|
|
16
16
|
const path = require('path')
|
|
17
17
|
const packagePath = path.join(process.cwd(), 'package.json')
|
|
18
18
|
const pkgJSON = JSON.parse(fs.readFileSync(packagePath))
|
|
19
|
-
const locale = process.argv[2]
|
|
20
19
|
|
|
21
20
|
const getAllFilesByExtensions = (dirPath, arrayOfFiles = [], extensions = []) => {
|
|
22
|
-
const files = fs.readdirSync(dirPath)
|
|
21
|
+
const files = fs.readdirSync(dirPath, {withFileTypes: true})
|
|
23
22
|
|
|
24
23
|
files.forEach(function (file) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
31
|
-
} else {
|
|
32
|
-
arrayOfFiles.push(path.join(dirPath, file))
|
|
24
|
+
const filePath = path.join(dirPath, file.name)
|
|
25
|
+
if (file.isDirectory()) {
|
|
26
|
+
arrayOfFiles = getAllFilesByExtensions(filePath, arrayOfFiles, extensions)
|
|
27
|
+
} else if (extensions.length === 0 || extensions.includes(path.extname(filePath))) {
|
|
28
|
+
arrayOfFiles.push(filePath)
|
|
33
29
|
}
|
|
34
30
|
})
|
|
35
|
-
if (extensions.length) {
|
|
36
|
-
return arrayOfFiles.filter((filePath) => {
|
|
37
|
-
const getExtension = path.extname(filePath).replace('.', '')
|
|
38
|
-
return extensions.includes(getExtension)
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
31
|
|
|
42
32
|
return arrayOfFiles
|
|
43
33
|
}
|
|
44
34
|
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
function extract(locale) {
|
|
36
|
+
// `extends` is a reserved word (`class A extends B {}`)
|
|
37
|
+
const {extends: extendsPkg, overridesDir} = pkgJSON.ccExtensibility || {}
|
|
47
38
|
if (!overridesDir) {
|
|
48
|
-
const command =
|
|
39
|
+
const command = [
|
|
40
|
+
'formatjs extract "app/**/*.{js,jsx,ts,tsx}"',
|
|
41
|
+
`--out-file translations/${locale}.json`,
|
|
42
|
+
'--id-interpolation-pattern [sha512:contenthash:base64:6]'
|
|
43
|
+
].join(' ')
|
|
49
44
|
exec(command, (err) => {
|
|
50
45
|
if (err) {
|
|
51
46
|
console.error(err)
|
|
52
47
|
}
|
|
53
48
|
})
|
|
54
49
|
} else {
|
|
55
|
-
const overridesPath = path.join(process.cwd(),
|
|
50
|
+
const overridesPath = path.join(process.cwd(), overridesDir)
|
|
56
51
|
// get all the files in extended app
|
|
57
52
|
const files = getAllFilesByExtensions(
|
|
58
53
|
path.join(overridesPath, 'app'),
|
|
59
54
|
[],
|
|
60
|
-
['js', 'jsx', 'ts', 'tsx']
|
|
55
|
+
['.js', '.jsx', '.ts', '.tsx']
|
|
61
56
|
)
|
|
62
57
|
// get the file names that are overridden in base template
|
|
63
58
|
const overriddenFiles = files
|
|
64
|
-
.map((path) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
overriddenFiles.forEach((filePath) => {
|
|
76
|
-
fs.rename(filePath, `${filePath}.ignore`, (err) => err && console.error(err))
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
const extractCommand = `formatjs extract "./node_modules/${pkgJSON.ccExtensibility?.extends}/app/**/*.{js,jsx,ts,tsx}" "${pkgJSON.ccExtensibility?.overridesDir}/app/**/*.{js,jsx,ts,tsx}" --out-file translations/${locale}.json --id-interpolation-pattern [sha512:contenthash:base64:6]`
|
|
59
|
+
.map((path) => path.replace(overridesDir, `node_modules/${extendsPkg}`))
|
|
60
|
+
.filter((file) => fs.existsSync(file))
|
|
61
|
+
const extractCommand = [
|
|
62
|
+
'formatjs extract',
|
|
63
|
+
'"./node_modules/${extendsPkg}/app/**/*.{js,jsx,ts,tsx}"',
|
|
64
|
+
'"${overridesDir}/app/**/*.{js,jsx,ts,tsx}"',
|
|
65
|
+
`--out-file translations/${locale}.json`,
|
|
66
|
+
'--id-interpolation-pattern [sha512:contenthash:base64:6]',
|
|
67
|
+
'--ignore',
|
|
68
|
+
...overriddenFiles.map((file) => `'${file}'`)
|
|
69
|
+
].join(' ')
|
|
80
70
|
exec(extractCommand, (err) => {
|
|
81
71
|
if (err) {
|
|
82
72
|
console.error(err)
|
|
83
73
|
}
|
|
84
|
-
// restore file names
|
|
85
|
-
overriddenFiles.forEach((filePath) => {
|
|
86
|
-
fs.rename(`${filePath}.ignore`, filePath, (err) => err && console.error(err))
|
|
87
|
-
})
|
|
88
74
|
})
|
|
89
75
|
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// example usage: node ./scripts/translations/extract-default-messages en-US en-GB
|
|
80
|
+
process.argv.slice(2).forEach(extract)
|
|
90
81
|
} catch (error) {
|
|
91
82
|
console.error(error)
|
|
92
83
|
}
|
package/translations/en-GB.json
CHANGED
|
@@ -543,6 +543,9 @@
|
|
|
543
543
|
"global.info.added_to_wishlist": {
|
|
544
544
|
"defaultMessage": "{quantity} {quantity, plural, one {item} other {items}} added to wishlist"
|
|
545
545
|
},
|
|
546
|
+
"global.info.already_in_wishlist": {
|
|
547
|
+
"defaultMessage": "Item is already in wishlist"
|
|
548
|
+
},
|
|
546
549
|
"global.info.removed_from_wishlist": {
|
|
547
550
|
"defaultMessage": "Item removed from wishlist"
|
|
548
551
|
},
|
|
@@ -1005,7 +1008,7 @@
|
|
|
1005
1008
|
"product_tile.assistive_msg.add_to_wishlist": {
|
|
1006
1009
|
"defaultMessage": "Add {product} to wishlist"
|
|
1007
1010
|
},
|
|
1008
|
-
"product_tile.assistive_msg.
|
|
1011
|
+
"product_tile.assistive_msg.remove_from_wishlist": {
|
|
1009
1012
|
"defaultMessage": "Remove {product} from wishlist"
|
|
1010
1013
|
},
|
|
1011
1014
|
"product_tile.label.starting_at_price": {
|