Skip to content

Commit cc0acae

Browse files
authored
Fix regression on loading the correct translation file (#193)
1 parent 9b64174 commit cc0acae

File tree

10 files changed

+69
-80
lines changed

10 files changed

+69
-80
lines changed

packages/pwa/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Enable adding wishlist item to the cart. [#158](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/158)
1010
- Enabling pseudo locale now affects only the loading of the translation messages. The rest of the app still knows about English and the other locales. [#177](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/177)
1111
- Allow individual Commerce API calls to pass in a different locale/currency and override the global value. [#177](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/177)
12+
- Fix regression with loading the correct translation file
1213

1314
## v1.1.0 (Sep 27, 2021)
1415

packages/pwa/app/components/_app-config/index.jsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import {
2121
} from '../../commerce-api/contexts'
2222
import {commerceAPIConfig} from '../../commerce-api.config'
2323
import {einsteinAPIConfig} from '../../einstein-api.config'
24-
import {DEFAULT_LOCALE, SUPPORTED_LOCALES, DEFAULT_CURRENCY} from '../../constants'
25-
import {getPreferredCurrency} from '../../utils/locale'
24+
import {DEFAULT_LOCALE, DEFAULT_CURRENCY} from '../../constants'
25+
import {getPreferredCurrency, getSupportedLocalesIds} from '../../utils/locale'
2626

2727
const apiConfig = {
2828
...commerceAPIConfig,
@@ -48,10 +48,8 @@ const getLocale = (locals = {}) => {
4848
const {pathname} = new URL(`http://hostname${originalUrl}`)
4949
let shortCode = pathname.split('/')[1]
5050

51-
// Ensure that the locale is in the seported list, otherwise return the default.
52-
shortCode = SUPPORTED_LOCALES.find((locale) => locale.id === shortCode)
53-
? shortCode
54-
: DEFAULT_LOCALE
51+
// Ensure that the locale is in the supported list, otherwise return the default.
52+
shortCode = getSupportedLocalesIds().includes(shortCode) ? shortCode : DEFAULT_LOCALE
5553

5654
return shortCode
5755
}

packages/pwa/app/components/_app/index.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ import {IntlProvider} from 'react-intl'
4242
// Others
4343
import {watchOnlineStatus, flatten} from '../../utils/utils'
4444
import {homeUrlBuilder, getUrlWithLocale} from '../../utils/url'
45-
import {getLocaleConfig, getPreferredCurrency} from '../../utils/locale'
46-
import {DEFAULT_CURRENCY, HOME_HREF, SUPPORTED_LOCALES} from '../../constants'
45+
import {getLocaleConfig, getPreferredCurrency, getSupportedLocalesIds} from '../../utils/locale'
46+
import {DEFAULT_CURRENCY, HOME_HREF} from '../../constants'
4747

4848
import Seo from '../seo'
4949
import useWishlist from '../../hooks/use-wishlist'
@@ -163,12 +163,12 @@ const App = (props) => {
163163

164164
{/* Urls for all localized versions of this page (including current page)
165165
For more details on hrefLang, see https://developers.google.com/search/docs/advanced/crawling/localized-versions */}
166-
{SUPPORTED_LOCALES.map((locale) => (
166+
{getSupportedLocalesIds().map((locale) => (
167167
<link
168168
rel="alternate"
169-
hrefLang={locale.id.toLowerCase()}
170-
href={`${appOrigin}${getUrlWithLocale(locale.id, {location})}`}
171-
key={locale.id}
169+
hrefLang={locale.toLowerCase()}
170+
href={`${appOrigin}${getUrlWithLocale(locale, {location})}`}
171+
key={locale}
172172
/>
173173
))}
174174
{/* A general locale as fallback. For example: "en" if default locale is "en-GB" */}

packages/pwa/app/components/_app/index.test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {Helmet} from 'react-helmet'
1010

1111
import App from './index.jsx'
1212
import {renderWithProviders} from '../../utils/test-utils'
13-
import {DEFAULT_LOCALE, SUPPORTED_LOCALES} from '../../constants'
13+
import {DEFAULT_LOCALE} from '../../constants'
14+
import {getSupportedLocalesIds} from '../../utils/locale.js'
1415

1516
let windowSpy
1617

@@ -66,7 +67,7 @@ describe('App', () => {
6667
const hasGeneralLocale = ({hrefLang}) => hrefLang === DEFAULT_LOCALE.slice(0, 2)
6768

6869
// `length + 2` because one for a general locale and the other with x-default value
69-
expect(hreflangLinks.length).toBe(SUPPORTED_LOCALES.length + 2)
70+
expect(hreflangLinks.length).toBe(getSupportedLocalesIds().length + 2)
7071

7172
expect(hreflangLinks.some((link) => hasGeneralLocale(link))).toBe(true)
7273
expect(hreflangLinks.some((link) => link.hrefLang === 'x-default')).toBe(true)

packages/pwa/app/components/drawer-menu/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import useCustomer from '../../commerce-api/hooks/useCustomer'
5252
import LoadingSpinner from '../loading-spinner'
5353

5454
import useNavigation from '../../hooks/use-navigation'
55-
import {SUPPORTED_LOCALES} from '../../constants'
55+
import {getSupportedLocalesIds} from '../../utils/locale'
5656

5757
// The FONT_SIZES and FONT_WEIGHTS constants are used to control the styling for
5858
// the accordion buttons as their current depth. In the below definition we assign
@@ -256,7 +256,7 @@ const DrawerMenu = ({isOpen, onClose = noop, onLogoClick = noop, root}) => {
256256
<LocaleSelector
257257
{...styles.localeSelector}
258258
selectedLocale={intl.locale}
259-
locales={SUPPORTED_LOCALES}
259+
locales={getSupportedLocalesIds()}
260260
onSelect={(newLocale) => {
261261
// Update the `locale` in the URL.
262262
const newUrl = getUrlWithLocale(newLocale, {

packages/pwa/app/components/footer/index.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import {useIntl} from 'react-intl'
2727
import LinksList from '../links-list'
2828
import SocialIcons from '../social-icons'
2929
import {HideOnDesktop, HideOnMobile} from '../responsive'
30-
import {SUPPORTED_LOCALES} from '../../constants'
3130
import {getUrlWithLocale} from '../../utils/url'
3231
import LocaleText from '../locale-text'
32+
import {getSupportedLocalesIds} from '../../utils/locale'
3333

3434
const Footer = ({...otherProps}) => {
3535
const styles = useMultiStyleConfig('Footer')
@@ -140,12 +140,12 @@ const Footer = ({...otherProps}) => {
140140
variant="filled"
141141
{...styles.localeDropdown}
142142
>
143-
{SUPPORTED_LOCALES.map((locale) => (
143+
{getSupportedLocalesIds().map((locale) => (
144144
<LocaleText
145145
as="option"
146-
value={locale.id}
147-
shortCode={locale.id}
148-
key={locale.id}
146+
value={locale}
147+
shortCode={locale}
148+
key={locale}
149149
/>
150150
))}
151151
</Select>

packages/pwa/app/components/locale-selector/index.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,18 @@ const LocaleSelector = ({
7878
<AccordionPanel>
7979
<Accordion allowToggle={true} {...styles.accordion}>
8080
{locales.map((locale) => (
81-
<AccordionItem border="none" key={locale.id}>
81+
<AccordionItem border="none" key={locale}>
8282
<AccordionButton
8383
{...styles.optionButton}
84-
onClick={() => onSelect(locale.id)}
84+
onClick={() => onSelect(locale)}
8585
>
8686
{/* Display flag icon if one exists */}
87-
{flags[locale.id]}
87+
{flags[locale]}
8888

8989
{/* Locale name */}
9090
<LocaleText
9191
{...styles.optionText}
92-
shortCode={locale.id}
92+
shortCode={locale}
9393
/>
9494

9595
{/* Selection indicator */}
@@ -115,7 +115,7 @@ LocaleSelector.propTypes = {
115115
/**
116116
* A complete list of all the locales supported. This array must have content.
117117
*/
118-
locales: PropTypes.array.isRequired,
118+
locales: PropTypes.arrayOf(PropTypes.string).isRequired,
119119
/**
120120
* The current locales shortcode.
121121
*/

packages/pwa/app/components/locale-selector/index.test.js

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,7 @@ import {fireEvent} from '@testing-library/react'
99
import LocaleSelector from './index'
1010
import {renderWithProviders} from '../../utils/test-utils'
1111

12-
const supportedLocales = [
13-
{
14-
id: 'en-GB',
15-
preferredCurrency: 'GBP'
16-
},
17-
{
18-
id: 'fr-FR',
19-
preferredCurrency: 'EUR'
20-
},
21-
{
22-
id: 'it-IT',
23-
preferredCurrency: 'EUR'
24-
},
25-
{
26-
id: 'zh-CN',
27-
preferredCurrency: 'CNY'
28-
},
29-
{
30-
id: 'ja-JP',
31-
preferredCurrency: 'JPY'
32-
}
33-
]
12+
const supportedLocales = ['en-GB', 'fr-FR', 'it-IT', 'zh-CN', 'ja-JP']
3413

3514
test('Renders LocaleSelector', () => {
3615
renderWithProviders(<LocaleSelector selectedLocale="en-GB" locales={supportedLocales} />)

packages/pwa/app/utils/locale.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,24 @@
77

88
import {SUPPORTED_LOCALES, DEFAULT_LOCALE} from '../constants'
99

10+
const supportedLocales = SUPPORTED_LOCALES.map((locale) => locale.id)
11+
12+
/**
13+
* @returns {string[]} short codes of all the app's supported locales
14+
*/
15+
export const getSupportedLocalesIds = () => supportedLocales
16+
1017
/**
1118
* Dynamically import the translations/messages for a given locale
19+
* @private
1220
* @param {string} locale - The locale code
1321
* @returns {Promise<Object>} The messages (compiled in AST format) in the given locale. If locale is not found, returns the default locale's messages.
1422
*/
1523
export const loadLocaleData = async (locale) => {
1624
// NOTE: the pseudo locale in this case is actually `en-XB` from react-intl. For more details:
1725
// - see our npm script `compile-translations:pseudo`
1826
// - and this react-intl PR: https://github.com/formatjs/formatjs/pull/2708
19-
const locales = [...SUPPORTED_LOCALES, 'en-XB']
27+
const locales = [...supportedLocales, 'en-XB']
2028
let localeToLoad
2129

2230
if (locales.includes(locale)) {
@@ -48,7 +56,7 @@ export const loadLocaleData = async (locale) => {
4856
*/
4957
export const getLocaleConfig = async ({getUserPreferredLocales} = {}) => {
5058
const preferredLocales = getUserPreferredLocales ? getUserPreferredLocales() : [DEFAULT_LOCALE]
51-
const targetLocale = whichLocaleToLoad(preferredLocales, SUPPORTED_LOCALES, DEFAULT_LOCALE)
59+
const targetLocale = whichLocaleToLoad(preferredLocales, supportedLocales, DEFAULT_LOCALE)
5260

5361
const messages = await loadLocaleData(
5462
typeof window === 'undefined'
@@ -60,7 +68,7 @@ export const getLocaleConfig = async ({getUserPreferredLocales} = {}) => {
6068

6169
return {
6270
app: {
63-
supportedLocales: SUPPORTED_LOCALES,
71+
supportedLocales,
6472
defaultLocale: DEFAULT_LOCALE,
6573
targetLocale
6674
},
@@ -73,16 +81,14 @@ export const getLocaleConfig = async ({getUserPreferredLocales} = {}) => {
7381

7482
/**
7583
* Decide which locale to load
84+
* @private
7685
* @param {string[]} preferredLocales - All locales that the user prefers
7786
* @param {string[]} supportedLocales - All locales that your app supports
7887
* @param {string} fallbackLocale - App's default locale
7988
* @returns {string} The target locale if there's a match. Otherwise, returns `fallbackLocale`.
8089
*/
8190
export const whichLocaleToLoad = (preferredLocales, supportedLocales, fallbackLocale) => {
82-
const targetLocale = preferredLocales.filter((perfLocale) =>
83-
supportedLocales.some((locale) => locale.id === perfLocale)
84-
)[0]
85-
91+
const targetLocale = preferredLocales.filter((locale) => supportedLocales.includes(locale))[0]
8692
return targetLocale || fallbackLocale
8793
}
8894

packages/pwa/app/utils/locale.test.js

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,59 @@
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8-
import {whichLocaleToLoad, loadLocaleData, getLocaleConfig, getPreferredCurrency} from './locale'
8+
import {
9+
whichLocaleToLoad,
10+
loadLocaleData,
11+
getLocaleConfig,
12+
getPreferredCurrency,
13+
getSupportedLocalesIds
14+
} from './locale'
915

1016
import {SUPPORTED_LOCALES, DEFAULT_LOCALE} from '../constants'
1117

18+
const supportedLocales = getSupportedLocalesIds()
1219
const nonSupportedLocale = 'nl-NL'
13-
const supportedLocale = SUPPORTED_LOCALES[0]
14-
const testMessageId = 'login-redirect.message.welcome'
20+
// Make sure this supported locale is not the default locale.
21+
// Otherwise, our code would fall back to default and incorrectly pass the tests
22+
const supportedLocale = supportedLocales[1]
23+
24+
const testId1 = 'login-redirect.message.welcome'
25+
const testId2 = 'homepage.message.welcome'
1526

1627
test('our assumptions before further testing', () => {
17-
expect(SUPPORTED_LOCALES.includes(nonSupportedLocale)).toBe(false)
28+
expect(supportedLocales.includes(nonSupportedLocale)).toBe(false)
1829
expect(DEFAULT_LOCALE).toBe('en-GB')
30+
expect(supportedLocale).not.toBe(DEFAULT_LOCALE)
1931
})
2032

2133
describe('whichLocaleToLoad', () => {
2234
test('default to fallback locale', () => {
23-
const locale = whichLocaleToLoad([nonSupportedLocale], SUPPORTED_LOCALES, DEFAULT_LOCALE)
35+
const locale = whichLocaleToLoad([nonSupportedLocale], supportedLocales, DEFAULT_LOCALE)
2436
expect(locale).toBe(DEFAULT_LOCALE)
2537
})
2638
test('matches one of the supported locales', () => {
27-
const locale = whichLocaleToLoad([supportedLocale], SUPPORTED_LOCALES, DEFAULT_LOCALE)
28-
expect(locale).toBe(supportedLocale.id)
29-
})
30-
test('case-insensitivity', () => {
31-
const locale = whichLocaleToLoad(
32-
[supportedLocale.id.toUpperCase()],
33-
SUPPORTED_LOCALES,
34-
DEFAULT_LOCALE
35-
)
36-
expect(locale).toBe(supportedLocale.id)
39+
const locale = whichLocaleToLoad([supportedLocale], supportedLocales, DEFAULT_LOCALE)
40+
expect(locale).toBe(supportedLocale)
3741
})
3842
})
3943

4044
describe('loadLocaleData', () => {
4145
test('default to English as the fallback locale', async () => {
4246
const messages = await loadLocaleData(nonSupportedLocale)
43-
expect(messages[testMessageId][0].value).toMatch(/login redirect/i)
47+
expect(messages[testId1][0].value).toMatch(/login redirect/i)
4448
})
4549
test('loading one of the supported locales', async () => {
4650
const messages = await loadLocaleData(supportedLocale)
47-
expect(messages[testMessageId]).toBeDefined()
51+
expect(messages[testId2]).toBeDefined()
4852
})
4953
test('loading the pseudo locale', async () => {
5054
const messages = await loadLocaleData('en-XB')
51-
expect(messages[testMessageId][0].value).toMatch(/^\[!! Ļŏĝĝĝíń Ŕèíŕèèèć !!]$/)
55+
expect(messages[testId1][0].value).toMatch(/^\[!! Ļŏĝĝĝíń Ŕèíŕèèèć !!]$/)
5256
})
5357
test('handling a not-found translation file', async () => {
54-
expect(SUPPORTED_LOCALES[1].id).not.toBe(DEFAULT_LOCALE)
58+
expect(supportedLocale).not.toBe(DEFAULT_LOCALE)
5559

56-
jest.mock(`../translations/compiled/${SUPPORTED_LOCALES[1].id}.json`, () => {
60+
jest.mock(`../translations/compiled/${supportedLocale}.json`, () => {
5761
throw new Error()
5862
})
5963

@@ -62,11 +66,11 @@ describe('loadLocaleData', () => {
6266
importDefaultLocale = true
6367
})
6468

65-
await loadLocaleData(SUPPORTED_LOCALES[1].id)
69+
await loadLocaleData(supportedLocale)
6670
expect(importDefaultLocale).toBe(true)
6771

6872
// Reset
69-
jest.unmock(`../translations/compiled/${SUPPORTED_LOCALES[1].id}.json`)
73+
jest.unmock(`../translations/compiled/${supportedLocale}.json`)
7074
jest.unmock(`../translations/compiled/${DEFAULT_LOCALE}.json`)
7175
})
7276
})
@@ -89,7 +93,7 @@ describe('getLocaleConfig', () => {
8993
expect(config.app.targetLocale).toBe(DEFAULT_LOCALE)
9094
})
9195
test('with getUserPreferredLocales parameter', async () => {
92-
const locale = SUPPORTED_LOCALES[1].id
96+
const locale = supportedLocale
9397
expect(locale).not.toBe(DEFAULT_LOCALE)
9498

9599
const config = await getLocaleConfig({
@@ -107,13 +111,13 @@ describe('getLocaleConfig', () => {
107111
// The app should still think its target locale is the default one
108112
expect(config.app.targetLocale).toBe(DEFAULT_LOCALE)
109113
// But the actual translation should be using the pseudo locale
110-
expect(config.messages[testMessageId][0].value).toMatch(/^\[!! Ļŏĝĝĝíń Ŕèíŕèèèć !!]$/)
114+
expect(config.messages[testId1][0].value).toMatch(/^\[!! Ļŏĝĝĝíń Ŕèíŕèèèć !!]$/)
111115
})
112116
})
113117

114118
describe('getCurrency', () => {
115119
test('returns the preferred currency for a supported locale', () => {
116-
const currency = getPreferredCurrency(supportedLocale.id)
120+
const currency = getPreferredCurrency(SUPPORTED_LOCALES[0].id)
117121
expect(currency).toBe(SUPPORTED_LOCALES[0].preferredCurrency)
118122
})
119123

0 commit comments

Comments
 (0)