@salesforce/retail-react-app 1.0.0-preview.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/.eslintignore +7 -0
- package/.eslintrc.js +25 -0
- package/.prettierignore +4 -0
- package/.prettierrc.yaml +7 -0
- package/CHANGELOG.md +173 -0
- package/LICENSE +14 -0
- package/README.md +48 -0
- package/app/assets/svg/account.svg +3 -0
- package/app/assets/svg/alert.svg +3 -0
- package/app/assets/svg/basket.svg +3 -0
- package/app/assets/svg/brand-logo.svg +10 -0
- package/app/assets/svg/cc-amex.svg +7 -0
- package/app/assets/svg/cc-cvv.svg +8 -0
- package/app/assets/svg/cc-discover.svg +14 -0
- package/app/assets/svg/cc-mastercard.svg +8 -0
- package/app/assets/svg/cc-visa.svg +11 -0
- package/app/assets/svg/check-circle.svg +3 -0
- package/app/assets/svg/check.svg +3 -0
- package/app/assets/svg/chevron-down.svg +3 -0
- package/app/assets/svg/chevron-left.svg +3 -0
- package/app/assets/svg/chevron-right.svg +3 -0
- package/app/assets/svg/chevron-up.svg +3 -0
- package/app/assets/svg/close.svg +3 -0
- package/app/assets/svg/dashboard.svg +4 -0
- package/app/assets/svg/figma-logo.svg +14 -0
- package/app/assets/svg/file.svg +3 -0
- package/app/assets/svg/filter.svg +3 -0
- package/app/assets/svg/flag-ca.svg +5 -0
- package/app/assets/svg/flag-cn.svg +19 -0
- package/app/assets/svg/flag-fr.svg +19 -0
- package/app/assets/svg/flag-gb.svg +16 -0
- package/app/assets/svg/flag-it.svg +29 -0
- package/app/assets/svg/flag-jp.svg +10 -0
- package/app/assets/svg/flag-us.svg +7 -0
- package/app/assets/svg/github-logo.svg +40 -0
- package/app/assets/svg/hamburger.svg +8 -0
- package/app/assets/svg/heart-solid.svg +7 -0
- package/app/assets/svg/heart.svg +3 -0
- package/app/assets/svg/info.svg +3 -0
- package/app/assets/svg/like.svg +4 -0
- package/app/assets/svg/location.svg +3 -0
- package/app/assets/svg/lock.svg +3 -0
- package/app/assets/svg/paypal.svg +19 -0
- package/app/assets/svg/plug.svg +3 -0
- package/app/assets/svg/plus.svg +3 -0
- package/app/assets/svg/receipt.svg +3 -0
- package/app/assets/svg/search.svg +8 -0
- package/app/assets/svg/signout.svg +3 -0
- package/app/assets/svg/social-facebook.svg +3 -0
- package/app/assets/svg/social-instagram.svg +3 -0
- package/app/assets/svg/social-pinterest.svg +4 -0
- package/app/assets/svg/social-twitter.svg +3 -0
- package/app/assets/svg/social-youtube.svg +3 -0
- package/app/assets/svg/user.svg +3 -0
- package/app/assets/svg/visibility-off.svg +5 -0
- package/app/assets/svg/visibility.svg +3 -0
- package/app/components/_app/index.jsx +401 -0
- package/app/components/_app/index.test.js +85 -0
- package/app/components/_app/partials/above-header.jsx +10 -0
- package/app/components/_app-config/index.jsx +125 -0
- package/app/components/_app-config/index.test.js +77 -0
- package/app/components/_error/index.jsx +142 -0
- package/app/components/_error/index.test.js +25 -0
- package/app/components/action-card/index.jsx +75 -0
- package/app/components/address-display/index.jsx +30 -0
- package/app/components/basic-tile/index.jsx +65 -0
- package/app/components/basic-tile/index.test.js +23 -0
- package/app/components/breadcrumb/index.jsx +67 -0
- package/app/components/breadcrumb/index.test.js +30 -0
- package/app/components/confirmation-modal/index.jsx +111 -0
- package/app/components/confirmation-modal/index.test.js +98 -0
- package/app/components/drawer-menu/index.jsx +405 -0
- package/app/components/drawer-menu/index.test.js +33 -0
- package/app/components/dynamic-image/index.jsx +56 -0
- package/app/components/field/index.jsx +161 -0
- package/app/components/footer/index.jsx +269 -0
- package/app/components/footer/index.test.js +22 -0
- package/app/components/forms/address-fields.jsx +49 -0
- package/app/components/forms/credit-card-fields.jsx +149 -0
- package/app/components/forms/form-action-buttons.jsx +55 -0
- package/app/components/forms/login-fields.jsx +31 -0
- package/app/components/forms/password-requirements.jsx +99 -0
- package/app/components/forms/post-checkout-registration-fields.jsx +43 -0
- package/app/components/forms/profile-fields.jsx +36 -0
- package/app/components/forms/promo-code-fields.jsx +43 -0
- package/app/components/forms/registration-fields.jsx +42 -0
- package/app/components/forms/reset-password-fields.jsx +31 -0
- package/app/components/forms/state-province-options.jsx +75 -0
- package/app/components/forms/update-password-fields.jsx +49 -0
- package/app/components/forms/useAddressFields.jsx +196 -0
- package/app/components/forms/useCreditCardFields.jsx +146 -0
- package/app/components/forms/useLoginFields.jsx +52 -0
- package/app/components/forms/useProfileFields.jsx +95 -0
- package/app/components/forms/usePromoCodeFields.jsx +39 -0
- package/app/components/forms/useRegistrationFields.jsx +136 -0
- package/app/components/forms/useResetPasswordFields.jsx +40 -0
- package/app/components/forms/useUpdatePasswordFields.jsx +89 -0
- package/app/components/header/index.jsx +290 -0
- package/app/components/header/index.test.js +217 -0
- package/app/components/hero/index.jsx +84 -0
- package/app/components/hero/index.test.js +40 -0
- package/app/components/icons/index.jsx +158 -0
- package/app/components/icons/index.test.js +20 -0
- package/app/components/image-gallery/index.jsx +176 -0
- package/app/components/image-gallery/index.test.js +485 -0
- package/app/components/item-variant/index.jsx +33 -0
- package/app/components/item-variant/item-attributes.jsx +107 -0
- package/app/components/item-variant/item-image.jsx +73 -0
- package/app/components/item-variant/item-name.jsx +28 -0
- package/app/components/item-variant/item-price.jsx +117 -0
- package/app/components/link/index.jsx +32 -0
- package/app/components/link/index.test.js +72 -0
- package/app/components/links-list/index.jsx +89 -0
- package/app/components/links-list/index.test.js +62 -0
- package/app/components/list-menu/index.jsx +280 -0
- package/app/components/list-menu/index.test.js +44 -0
- package/app/components/loading-spinner/index.jsx +46 -0
- package/app/components/locale-selector/index.jsx +124 -0
- package/app/components/locale-selector/index.test.js +37 -0
- package/app/components/locale-text/index.jsx +97 -0
- package/app/components/locale-text/index.test.js +36 -0
- package/app/components/login/index.jsx +96 -0
- package/app/components/nested-accordion/index.jsx +185 -0
- package/app/components/nested-accordion/index.test.js +98 -0
- package/app/components/offline-banner/index.jsx +40 -0
- package/app/components/offline-banner/index.test.js +15 -0
- package/app/components/offline-boundary/index.jsx +104 -0
- package/app/components/offline-boundary/index.test.js +123 -0
- package/app/components/order-summary/index.jsx +331 -0
- package/app/components/page-action-placeholder/index.jsx +50 -0
- package/app/components/pagination/index.jsx +134 -0
- package/app/components/pagination/index.test.js +25 -0
- package/app/components/product-item/index.jsx +146 -0
- package/app/components/product-item/index.test.js +38 -0
- package/app/components/product-scroller/index.jsx +172 -0
- package/app/components/product-scroller/index.test.js +98 -0
- package/app/components/product-tile/index.jsx +195 -0
- package/app/components/product-tile/index.test.js +96 -0
- package/app/components/product-view/index.jsx +538 -0
- package/app/components/product-view/index.test.js +224 -0
- package/app/components/product-view-modal/index.jsx +48 -0
- package/app/components/product-view-modal/index.test.js +72 -0
- package/app/components/promo-code/index.jsx +162 -0
- package/app/components/promo-popover/index.jsx +83 -0
- package/app/components/quantity-picker/index.jsx +58 -0
- package/app/components/radio-card/index.jsx +75 -0
- package/app/components/recommended-products/index.jsx +227 -0
- package/app/components/register/index.jsx +114 -0
- package/app/components/reset-password/index.jsx +87 -0
- package/app/components/responsive/index.jsx +29 -0
- package/app/components/scroll-to-top/index.jsx +24 -0
- package/app/components/scroll-to-top/index.test.js +46 -0
- package/app/components/search/index.jsx +279 -0
- package/app/components/search/index.test.js +127 -0
- package/app/components/search/partials/recent-searches.jsx +76 -0
- package/app/components/search/partials/search-suggestions.jsx +45 -0
- package/app/components/search/partials/suggestions.jsx +43 -0
- package/app/components/section/index.jsx +68 -0
- package/app/components/seo/index.jsx +33 -0
- package/app/components/social-icons/index.jsx +101 -0
- package/app/components/social-icons/index.test.js +30 -0
- package/app/components/swatch-group/index.jsx +77 -0
- package/app/components/swatch-group/index.test.js +136 -0
- package/app/components/swatch-group/swatch.jsx +94 -0
- package/app/components/toggle-card/index.jsx +97 -0
- package/app/components/with-registration/index.jsx +58 -0
- package/app/components/with-registration/index.test.js +85 -0
- package/app/constants.js +109 -0
- package/app/contexts/index.js +92 -0
- package/app/hooks/einstein-mock-data.js +916 -0
- package/app/hooks/index.js +17 -0
- package/app/hooks/use-add-to-cart-modal.js +344 -0
- package/app/hooks/use-add-to-cart-modal.test.js +625 -0
- package/app/hooks/use-auth-modal.js +337 -0
- package/app/hooks/use-auth-modal.test.js +365 -0
- package/app/hooks/use-currency.js +20 -0
- package/app/hooks/use-currency.test.js +41 -0
- package/app/hooks/use-current-basket.js +39 -0
- package/app/hooks/use-current-customer.js +29 -0
- package/app/hooks/use-derived-product.js +77 -0
- package/app/hooks/use-derived-product.test.js +69 -0
- package/app/hooks/use-einstein.js +512 -0
- package/app/hooks/use-einstein.test.js +224 -0
- package/app/hooks/use-intersection-observer.js +64 -0
- package/app/hooks/use-limit-urls.js +31 -0
- package/app/hooks/use-limit-urls.test.js +40 -0
- package/app/hooks/use-multi-site.js +36 -0
- package/app/hooks/use-multi-site.test.js +53 -0
- package/app/hooks/use-navigation.js +37 -0
- package/app/hooks/use-navigation.test.js +109 -0
- package/app/hooks/use-page-urls.js +35 -0
- package/app/hooks/use-page-urls.test.js +39 -0
- package/app/hooks/use-pdp-search-params.js +16 -0
- package/app/hooks/use-pdp-search-params.test.js +52 -0
- package/app/hooks/use-previous.js +17 -0
- package/app/hooks/use-product-view-modal.js +93 -0
- package/app/hooks/use-product-view-modal.test.js +172 -0
- package/app/hooks/use-search-params.js +96 -0
- package/app/hooks/use-search-params.test.js +91 -0
- package/app/hooks/use-sort-urls.js +33 -0
- package/app/hooks/use-sort-urls.test.js +42 -0
- package/app/hooks/use-toast.js +68 -0
- package/app/hooks/use-toast.test.js +58 -0
- package/app/hooks/use-variant.js +32 -0
- package/app/hooks/use-variant.test.js +81 -0
- package/app/hooks/use-variation-attributes.js +138 -0
- package/app/hooks/use-variation-attributes.test.js +119 -0
- package/app/hooks/use-variation-params.js +31 -0
- package/app/hooks/use-variation-params.test.js +73 -0
- package/app/hooks/use-wish-list.js +42 -0
- package/app/main.jsx +14 -0
- package/app/mocks/basket-with-suit.js +146 -0
- package/app/mocks/empty-basket.js +39 -0
- package/app/mocks/mock-data.js +5632 -0
- package/app/mocks/product-set-winter-lookM.js +1224 -0
- package/app/mocks/searchResults.js +144 -0
- package/app/mocks/variant-750518699578M.js +434 -0
- package/app/page-designer/README.md +102 -0
- package/app/page-designer/assets/image-tile/index.jsx +51 -0
- package/app/page-designer/assets/image-tile/index.test.js +30 -0
- package/app/page-designer/assets/image-with-text/index.jsx +140 -0
- package/app/page-designer/assets/image-with-text/index.test.js +38 -0
- package/app/page-designer/assets/index.js +9 -0
- package/app/page-designer/index.js +10 -0
- package/app/page-designer/layouts/carousel/index.jsx +222 -0
- package/app/page-designer/layouts/carousel/index.test.js +43 -0
- package/app/page-designer/layouts/index.js +14 -0
- package/app/page-designer/layouts/mobileGrid1r1c/index.jsx +36 -0
- package/app/page-designer/layouts/mobileGrid1r1c/index.test.js +35 -0
- package/app/page-designer/layouts/mobileGrid2r1c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid2r1c/index.test.js +47 -0
- package/app/page-designer/layouts/mobileGrid2r2c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid2r2c/index.test.js +71 -0
- package/app/page-designer/layouts/mobileGrid2r3c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid2r3c/index.test.js +95 -0
- package/app/page-designer/layouts/mobileGrid3r1c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid3r1c/index.test.js +59 -0
- package/app/page-designer/layouts/mobileGrid3r2c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid3r2c/index.test.js +95 -0
- package/app/page-designer/utils.js +14 -0
- package/app/pages/account/addresses.jsx +382 -0
- package/app/pages/account/addresses.test.js +120 -0
- package/app/pages/account/constant.js +57 -0
- package/app/pages/account/index.jsx +237 -0
- package/app/pages/account/index.test.js +188 -0
- package/app/pages/account/order-detail.jsx +397 -0
- package/app/pages/account/order-history.jsx +264 -0
- package/app/pages/account/orders.jsx +30 -0
- package/app/pages/account/orders.test.js +95 -0
- package/app/pages/account/profile.jsx +357 -0
- package/app/pages/account/wishlist/index.jsx +195 -0
- package/app/pages/account/wishlist/index.mock.js +1481 -0
- package/app/pages/account/wishlist/index.test.js +56 -0
- package/app/pages/account/wishlist/partials/wishlist-primary-action.jsx +170 -0
- package/app/pages/account/wishlist/partials/wishlist-primary-action.mock.js +1623 -0
- package/app/pages/account/wishlist/partials/wishlist-primary-action.test.js +99 -0
- package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.jsx +120 -0
- package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.test.js +391 -0
- package/app/pages/cart/index.jsx +476 -0
- package/app/pages/cart/index.test.js +481 -0
- package/app/pages/cart/partials/cart-cta.jsx +46 -0
- package/app/pages/cart/partials/cart-secondary-button-group.jsx +135 -0
- package/app/pages/cart/partials/cart-secondary-button-group.test.js +103 -0
- package/app/pages/cart/partials/cart-skeleton.jsx +93 -0
- package/app/pages/cart/partials/cart-title.jsx +27 -0
- package/app/pages/cart/partials/empty-cart.jsx +86 -0
- package/app/pages/checkout/confirmation.jsx +541 -0
- package/app/pages/checkout/confirmation.mock.js +450 -0
- package/app/pages/checkout/confirmation.test.js +114 -0
- package/app/pages/checkout/index.jsx +169 -0
- package/app/pages/checkout/index.test.js +582 -0
- package/app/pages/checkout/partials/cc-radio-group.jsx +122 -0
- package/app/pages/checkout/partials/checkout-footer.jsx +140 -0
- package/app/pages/checkout/partials/checkout-footer.test.js +16 -0
- package/app/pages/checkout/partials/checkout-header.jsx +54 -0
- package/app/pages/checkout/partials/checkout-header.test.js +16 -0
- package/app/pages/checkout/partials/checkout-skeleton.jsx +52 -0
- package/app/pages/checkout/partials/contact-info.jsx +251 -0
- package/app/pages/checkout/partials/contact-info.test.js +43 -0
- package/app/pages/checkout/partials/payment-form.jsx +97 -0
- package/app/pages/checkout/partials/payment.jsx +276 -0
- package/app/pages/checkout/partials/shipping-address-selection.jsx +377 -0
- package/app/pages/checkout/partials/shipping-address.jsx +132 -0
- package/app/pages/checkout/partials/shipping-options.jsx +232 -0
- package/app/pages/checkout/util/checkout-context.js +94 -0
- package/app/pages/home/data.js +134 -0
- package/app/pages/home/index.jsx +301 -0
- package/app/pages/home/index.test.js +23 -0
- package/app/pages/login/index.jsx +123 -0
- package/app/pages/login/index.test.js +229 -0
- package/app/pages/login-redirect/index.jsx +23 -0
- package/app/pages/login-redirect/index.test.js +16 -0
- package/app/pages/page-not-found/index.jsx +90 -0
- package/app/pages/page-not-found/index.test.js +31 -0
- package/app/pages/product-detail/index.jsx +394 -0
- package/app/pages/product-detail/index.mock.js +197 -0
- package/app/pages/product-detail/index.test.js +162 -0
- package/app/pages/product-detail/partials/information-accordion.jsx +121 -0
- package/app/pages/product-list/index.jsx +735 -0
- package/app/pages/product-list/index.test.js +180 -0
- package/app/pages/product-list/partials/above-page-header.jsx +10 -0
- package/app/pages/product-list/partials/checkbox-refinements.jsx +41 -0
- package/app/pages/product-list/partials/checkbox-refinements.test.js +53 -0
- package/app/pages/product-list/partials/color-refinements.jsx +88 -0
- package/app/pages/product-list/partials/empty-results.jsx +118 -0
- package/app/pages/product-list/partials/link-refinements.jsx +38 -0
- package/app/pages/product-list/partials/page-header.jsx +42 -0
- package/app/pages/product-list/partials/radio-refinements.jsx +60 -0
- package/app/pages/product-list/partials/refinements.jsx +144 -0
- package/app/pages/product-list/partials/selected-refinements.jsx +100 -0
- package/app/pages/product-list/partials/size-refinements.jsx +55 -0
- package/app/pages/registration/index.jsx +87 -0
- package/app/pages/registration/index.test.jsx +132 -0
- package/app/pages/reset-password/index.jsx +112 -0
- package/app/pages/reset-password/index.test.jsx +141 -0
- package/app/request-processor.js +118 -0
- package/app/request-processor.test.js +23 -0
- package/app/routes.jsx +111 -0
- package/app/routes.test.js +13 -0
- package/app/ssr.js +70 -0
- package/app/static/ico/favicon.ico +0 -0
- package/app/static/img/global/app-icon-192.png +0 -0
- package/app/static/img/global/app-icon-512.png +0 -0
- package/app/static/img/global/apple-touch-icon.png +0 -0
- package/app/static/img/hero.png +0 -0
- package/app/static/manifest.json +19 -0
- package/app/static/robots.txt +2 -0
- package/app/theme/components/base/accordion.js +21 -0
- package/app/theme/components/base/alert.js +17 -0
- package/app/theme/components/base/badge.js +25 -0
- package/app/theme/components/base/button.js +77 -0
- package/app/theme/components/base/checkbox.js +30 -0
- package/app/theme/components/base/container.js +17 -0
- package/app/theme/components/base/drawer.js +26 -0
- package/app/theme/components/base/formLabel.js +13 -0
- package/app/theme/components/base/icon.js +13 -0
- package/app/theme/components/base/input.js +44 -0
- package/app/theme/components/base/modal.js +11 -0
- package/app/theme/components/base/popover.js +61 -0
- package/app/theme/components/base/radio.js +33 -0
- package/app/theme/components/base/select.js +15 -0
- package/app/theme/components/base/skeleton.js +12 -0
- package/app/theme/components/base/tooltip.js +19 -0
- package/app/theme/components/project/_app.js +25 -0
- package/app/theme/components/project/breadcrumb.js +25 -0
- package/app/theme/components/project/checkout-footer.js +35 -0
- package/app/theme/components/project/drawer-menu.js +66 -0
- package/app/theme/components/project/footer.js +84 -0
- package/app/theme/components/project/header.js +84 -0
- package/app/theme/components/project/image-gallery.js +59 -0
- package/app/theme/components/project/links-list.js +43 -0
- package/app/theme/components/project/list-menu.js +91 -0
- package/app/theme/components/project/locale-selector.js +42 -0
- package/app/theme/components/project/nested-accordion.js +26 -0
- package/app/theme/components/project/offline-banner.js +25 -0
- package/app/theme/components/project/pagination.js +22 -0
- package/app/theme/components/project/product-tile.js +32 -0
- package/app/theme/components/project/social-icons.js +52 -0
- package/app/theme/components/project/swatch-group.js +115 -0
- package/app/theme/foundations/colors.js +170 -0
- package/app/theme/foundations/gradients.js +9 -0
- package/app/theme/foundations/layerStyles.js +41 -0
- package/app/theme/foundations/shadows.js +9 -0
- package/app/theme/foundations/sizes.js +18 -0
- package/app/theme/foundations/space.js +9 -0
- package/app/theme/foundations/styles.js +21 -0
- package/app/theme/index.js +104 -0
- package/app/utils/cc-utils.js +112 -0
- package/app/utils/cc-utils.test.js +41 -0
- package/app/utils/image-groups-utils.js +62 -0
- package/app/utils/image-groups-utils.test.js +65 -0
- package/app/utils/locale.js +78 -0
- package/app/utils/locale.test.js +112 -0
- package/app/utils/password-utils.js +21 -0
- package/app/utils/phone-utils.js +22 -0
- package/app/utils/phone-utils.test.js +15 -0
- package/app/utils/product-utils.js +35 -0
- package/app/utils/product-utils.test.js +51 -0
- package/app/utils/responsive-image.js +198 -0
- package/app/utils/responsive-image.test.js +170 -0
- package/app/utils/routes-utils.js +111 -0
- package/app/utils/routes-utils.test.js +291 -0
- package/app/utils/site-utils.js +222 -0
- package/app/utils/site-utils.test.js +376 -0
- package/app/utils/test-utils.js +257 -0
- package/app/utils/url.js +291 -0
- package/app/utils/url.test.js +421 -0
- package/app/utils/utils.js +201 -0
- package/app/utils/utils.test.js +182 -0
- package/babel.config.js +7 -0
- package/cache-hash-config.json +8 -0
- package/config/default.js +64 -0
- package/config/mocks/default.js +131 -0
- package/config/sites.js +78 -0
- package/jest-setup.js +191 -0
- package/jest.config.js +50 -0
- package/jsconfig.json +13 -0
- package/package.json +105 -0
- package/scripts/extract-default-messages.js +92 -0
- package/tests/lighthouserc.js +37 -0
- package/translations/README.md +127 -0
- package/translations/compiled/de-DE.json +3212 -0
- package/translations/compiled/en-GB.json +3212 -0
- package/translations/compiled/en-US.json +3212 -0
- package/translations/compiled/en-XA.json +6948 -0
- package/translations/compiled/es-MX.json +3216 -0
- package/translations/compiled/fr-FR.json +3216 -0
- package/translations/compiled/it-IT.json +3188 -0
- package/translations/compiled/ja-JP.json +3200 -0
- package/translations/compiled/ko-KR.json +3180 -0
- package/translations/compiled/pt-BR.json +3220 -0
- package/translations/compiled/zh-CN.json +3212 -0
- package/translations/compiled/zh-TW.json +3208 -0
- package/translations/de-DE.json +1417 -0
- package/translations/en-GB.json +1417 -0
- package/translations/en-US.json +1417 -0
- package/translations/es-MX.json +1417 -0
- package/translations/fr-FR.json +1417 -0
- package/translations/it-IT.json +1417 -0
- package/translations/ja-JP.json +1417 -0
- package/translations/ko-KR.json +1417 -0
- package/translations/pt-BR.json +1417 -0
- package/translations/zh-CN.json +1417 -0
- package/translations/zh-TW.json +1417 -0
- package/worker/main.js +36 -0
package/jest.config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path')
|
|
9
|
+
const base = require('@salesforce/pwa-kit-dev/configs/jest/jest.config.js')
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
...base,
|
|
13
|
+
moduleNameMapper: {
|
|
14
|
+
...base.moduleNameMapper,
|
|
15
|
+
'^react$': '<rootDir>/node_modules/react/index.js',
|
|
16
|
+
'^react-router-dom(.*)$': '<rootDir>/node_modules/react-router-dom/index.js',
|
|
17
|
+
'^@salesforce\/retail-react-app(.*)$': '<rootDir>$1',
|
|
18
|
+
'^@tanstack/react-query$':
|
|
19
|
+
'<rootDir>/node_modules/@tanstack/react-query/build/lib/index.js',
|
|
20
|
+
'^is-what$': '<rootDir>/node_modules/is-what/dist/cjs/index.cjs',
|
|
21
|
+
'^copy-anything$': '<rootDir>/node_modules/copy-anything/dist/cjs/index.cjs'
|
|
22
|
+
},
|
|
23
|
+
setupFilesAfterEnv: [path.join(__dirname, 'jest-setup.js')],
|
|
24
|
+
collectCoverageFrom: [
|
|
25
|
+
'app/**/*.{js,jsx}',
|
|
26
|
+
'non-pwa/**/*.{js,jsx}',
|
|
27
|
+
'worker/**/*.{js,jsx}',
|
|
28
|
+
'scripts/generator/*.{js,jsx}',
|
|
29
|
+
'!app/pages/test-container/**/*.{js,jsx}',
|
|
30
|
+
'!app/utils/test-utils.js',
|
|
31
|
+
'!app/mocks/*.js',
|
|
32
|
+
'!app/main.jsx',
|
|
33
|
+
'!app/loader.js',
|
|
34
|
+
'!app/ssr.js',
|
|
35
|
+
'!app/static/**',
|
|
36
|
+
'!app/theme/**',
|
|
37
|
+
'!node_modules/**'
|
|
38
|
+
],
|
|
39
|
+
//@TODO: Revert this threshold back to original numbers stattements: 80, branches: 72, functions: 78, lines: 83
|
|
40
|
+
coverageThreshold: {
|
|
41
|
+
global: {
|
|
42
|
+
statements: 73,
|
|
43
|
+
branches: 60,
|
|
44
|
+
functions: 65,
|
|
45
|
+
lines: 74
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
// Increase to: 6 x default timeout of 5 seconds
|
|
49
|
+
...(process.env.CI ? {testTimeout: 30000} : {})
|
|
50
|
+
}
|
package/jsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// for development convenience, this file helps IDE's find relative paths prefixed with
|
|
2
|
+
// the self-reference (to this package) 'retail-react-app'
|
|
3
|
+
|
|
4
|
+
// jsconfig.json
|
|
5
|
+
{
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"target": "ES6",
|
|
8
|
+
"baseUrl": "./",
|
|
9
|
+
"paths": {
|
|
10
|
+
"retail-react-app/*": ["./*"]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salesforce/retail-react-app",
|
|
3
|
+
"version": "1.0.0-preview.0",
|
|
4
|
+
"license": "See license in LICENSE",
|
|
5
|
+
"author": "cc-pwa-kit@salesforce.com",
|
|
6
|
+
"ccExtensibility": {
|
|
7
|
+
"extendable": [
|
|
8
|
+
"@salesforce/retail-react-app"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"analyze-build": "cross-env MOBIFY_ANALYZE=true npm run build",
|
|
13
|
+
"build": "npm run build-translations && pwa-kit-dev build",
|
|
14
|
+
"build-translations": "npm run extract-default-translations && npm run compile-translations",
|
|
15
|
+
"compile-translations": "formatjs compile-folder --ast translations translations/compiled",
|
|
16
|
+
"compile-translations:pseudo": "formatjs compile --ast translations/en-US.json --out-file translations/compiled/en-XA.json --pseudo-locale en-XA",
|
|
17
|
+
"extract-default-translations": "node ./scripts/extract-default-messages.js en-US",
|
|
18
|
+
"format": "pwa-kit-dev format \"**/*.{js,jsx}\"",
|
|
19
|
+
"lint": "pwa-kit-dev lint \"**/*.{js,jsx}\"",
|
|
20
|
+
"lint:fix": "npm run lint -- --fix",
|
|
21
|
+
"push": "npm run build && pwa-kit-dev push",
|
|
22
|
+
"save-credentials": "pwa-kit-dev save-credentials",
|
|
23
|
+
"start": "cross-env NODE_ICU_DATA=node_modules/full-icu pwa-kit-dev start",
|
|
24
|
+
"start:inspect": "npm run start -- --inspect",
|
|
25
|
+
"start:pseudolocale": "npm run extract-default-translations && npm run compile-translations:pseudo && cross-env USE_PSEUDOLOCALE=true npm run start",
|
|
26
|
+
"tail-logs": "pwa-kit-dev tail-logs",
|
|
27
|
+
"test": "pwa-kit-dev test",
|
|
28
|
+
"test:lighthouse": "cross-env NODE_ENV=production lhci autorun --config=tests/lighthouserc.js",
|
|
29
|
+
"test:max-file-size": "npm run build && bundlesize"
|
|
30
|
+
},
|
|
31
|
+
"browserslist": [
|
|
32
|
+
"iOS >= 9.0",
|
|
33
|
+
"Android >= 4.4.4",
|
|
34
|
+
"last 4 ChromeAndroid versions"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@chakra-ui/icons": "^2.0.19",
|
|
38
|
+
"@chakra-ui/react": "^2.6.0",
|
|
39
|
+
"@chakra-ui/skip-nav": "^2.0.15",
|
|
40
|
+
"@chakra-ui/system": "^2.5.6",
|
|
41
|
+
"@emotion/react": "^11.10.6",
|
|
42
|
+
"@emotion/styled": "^11.10.6",
|
|
43
|
+
"@formatjs/cli": "^6.0.4",
|
|
44
|
+
"@lhci/cli": "^0.11.0",
|
|
45
|
+
"@loadable/component": "^5.15.3",
|
|
46
|
+
"@peculiar/webcrypto": "^1.4.2",
|
|
47
|
+
"@salesforce/commerce-sdk-react": "1.0.0-preview.0",
|
|
48
|
+
"@salesforce/pwa-kit-dev": "3.0.0-preview.0",
|
|
49
|
+
"@salesforce/pwa-kit-react-sdk": "3.0.0-preview.0",
|
|
50
|
+
"@salesforce/pwa-kit-runtime": "3.0.0-preview.0",
|
|
51
|
+
"@tanstack/react-query": "^4.0.10",
|
|
52
|
+
"@tanstack/react-query-devtools": "^4.29.1",
|
|
53
|
+
"@testing-library/dom": "^9.0.1",
|
|
54
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
55
|
+
"@testing-library/react": "^14.0.0",
|
|
56
|
+
"@testing-library/user-event": "^14.4.3",
|
|
57
|
+
"base64-arraybuffer": "^0.2.0",
|
|
58
|
+
"bundlesize2": "^0.0.31",
|
|
59
|
+
"card-validator": "^8.1.1",
|
|
60
|
+
"cross-env": "^5.2.1",
|
|
61
|
+
"focus-visible": "^5.2.0",
|
|
62
|
+
"framer-motion": "^10.12.9",
|
|
63
|
+
"full-icu": "^1.5.0",
|
|
64
|
+
"helmet": "^4.6.0",
|
|
65
|
+
"jest-fetch-mock": "^2.1.2",
|
|
66
|
+
"js-cookie": "^3.0.1",
|
|
67
|
+
"jsonwebtoken": "^9.0.0",
|
|
68
|
+
"jwt-decode": "^3.1.2",
|
|
69
|
+
"lodash": "^4.17.21",
|
|
70
|
+
"msw": "^1.2.1",
|
|
71
|
+
"nanoid": "^3.3.4",
|
|
72
|
+
"njwt": "^1.2.0",
|
|
73
|
+
"prop-types": "^15.8.1",
|
|
74
|
+
"query-string": "^7.1.3",
|
|
75
|
+
"raf": "^3.4.1",
|
|
76
|
+
"randomstring": "^1.2.3",
|
|
77
|
+
"react": "^18.2.0",
|
|
78
|
+
"react-dom": "^18.2.0",
|
|
79
|
+
"react-helmet": "^6.1.0",
|
|
80
|
+
"react-hook-form": "^7.43.9",
|
|
81
|
+
"react-intl": "^5.25.1",
|
|
82
|
+
"react-router-dom": "^5.3.4"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"cross-env": "^5.2.1"
|
|
86
|
+
},
|
|
87
|
+
"engines": {
|
|
88
|
+
"node": "^16.11.0 || ^18.0.0",
|
|
89
|
+
"npm": "^8.0.0 || ^9.0.0"
|
|
90
|
+
},
|
|
91
|
+
"bundlesize": [
|
|
92
|
+
{
|
|
93
|
+
"path": "build/main.js",
|
|
94
|
+
"maxSize": "42 kB"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"path": "build/vendor.js",
|
|
98
|
+
"maxSize": "320 kB"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"overrides": {
|
|
102
|
+
"nwsapi": "2.2.2"
|
|
103
|
+
},
|
|
104
|
+
"gitHead": "a9f820893b7714244a0af509a5aefecc1344153c"
|
|
105
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023, Salesforce, Inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
6
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
/* eslint @typescript-eslint/no-var-requires: "off" */
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This script will extract messages from base template and extended app and output all translations in the extended app
|
|
12
|
+
* If a file is overridden, it won't extract messages from that file in the base template
|
|
13
|
+
*/
|
|
14
|
+
const {exec} = require('child_process')
|
|
15
|
+
const fs = require('fs')
|
|
16
|
+
const path = require('path')
|
|
17
|
+
const packagePath = path.join(process.cwd(), 'package.json')
|
|
18
|
+
const pkgJSON = JSON.parse(fs.readFileSync(packagePath))
|
|
19
|
+
const locale = process.argv[2]
|
|
20
|
+
|
|
21
|
+
const getAllFilesByExtensions = (dirPath, arrayOfFiles = [], extensions = []) => {
|
|
22
|
+
const files = fs.readdirSync(dirPath)
|
|
23
|
+
|
|
24
|
+
files.forEach(function (file) {
|
|
25
|
+
if (fs.statSync(path.join(dirPath, file)).isDirectory()) {
|
|
26
|
+
arrayOfFiles = getAllFilesByExtensions(
|
|
27
|
+
path.join(dirPath, file),
|
|
28
|
+
arrayOfFiles,
|
|
29
|
+
extensions
|
|
30
|
+
)
|
|
31
|
+
} else {
|
|
32
|
+
arrayOfFiles.push(path.join(dirPath, file))
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
if (extensions.length) {
|
|
36
|
+
return arrayOfFiles.filter((filePath) => {
|
|
37
|
+
const getExtension = path.extname(filePath).replace('.', '')
|
|
38
|
+
return extensions.includes(getExtension)
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return arrayOfFiles
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const overridesDir = pkgJSON.ccExtensibility?.overridesDir
|
|
47
|
+
if (!overridesDir) {
|
|
48
|
+
const command = `formatjs extract "app/**/*.{js,jsx,ts,tsx}" --out-file translations/${locale}.json --id-interpolation-pattern [sha512:contenthash:base64:6]`
|
|
49
|
+
exec(command, (err) => {
|
|
50
|
+
if (err) {
|
|
51
|
+
console.error(err)
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
} else {
|
|
55
|
+
const overridesPath = path.join(process.cwd(), pkgJSON.ccExtensibility?.overridesDir)
|
|
56
|
+
// get all the files in extended app
|
|
57
|
+
const files = getAllFilesByExtensions(
|
|
58
|
+
path.join(overridesPath, 'app'),
|
|
59
|
+
[],
|
|
60
|
+
['js', 'jsx', 'ts', 'tsx']
|
|
61
|
+
)
|
|
62
|
+
// get the file names that are overridden in base template
|
|
63
|
+
const overriddenFiles = files
|
|
64
|
+
.map((path) => {
|
|
65
|
+
const replacedPath = path.replace(
|
|
66
|
+
overridesDir,
|
|
67
|
+
`node_modules/${pkgJSON.ccExtensibility?.extends}`
|
|
68
|
+
)
|
|
69
|
+
// check if this file does exist in base template
|
|
70
|
+
const isFileExist = fs.existsSync(replacedPath)
|
|
71
|
+
return isFileExist ? replacedPath : ''
|
|
72
|
+
})
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
// rename the files needs to ignore to have .ignore extensions so it won't be recognized by formatjs
|
|
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]`
|
|
80
|
+
exec(extractCommand, (err) => {
|
|
81
|
+
if (err) {
|
|
82
|
+
console.error(err)
|
|
83
|
+
}
|
|
84
|
+
// restore file names
|
|
85
|
+
overriddenFiles.forEach((filePath) => {
|
|
86
|
+
fs.rename(`${filePath}.ignore`, filePath, (err) => err && console.error(err))
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(error)
|
|
92
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
module.exports = {
|
|
8
|
+
// The different Lighthouse CI configuration options:
|
|
9
|
+
// https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/configuration.md
|
|
10
|
+
ci: {
|
|
11
|
+
collect: {
|
|
12
|
+
startServerCommand: 'npm run start',
|
|
13
|
+
//NOTE: Adjust the key pages URLs that you find important to your website.
|
|
14
|
+
url: [
|
|
15
|
+
'http://localhost:3000/',
|
|
16
|
+
'http://localhost:3000/global/en-GB/category/womens',
|
|
17
|
+
'http://localhost:3000/global/en-GB/product/25493613M',
|
|
18
|
+
'http://localhost:3000/global/en-GB/search?q=suit'
|
|
19
|
+
],
|
|
20
|
+
startServerReadyPattern: 'First build complete',
|
|
21
|
+
startServerReadyTimeout: 90000
|
|
22
|
+
},
|
|
23
|
+
upload: {
|
|
24
|
+
target: 'temporary-public-storage'
|
|
25
|
+
},
|
|
26
|
+
assert: {
|
|
27
|
+
aggregationMethod: 'median',
|
|
28
|
+
assertions: {
|
|
29
|
+
// NOTE: Adjust the scores accordingly as the performance is improved
|
|
30
|
+
'categories:performance': ['error', {minScore: 0.3}],
|
|
31
|
+
'categories:pwa': ['error', {minScore: 0.9}],
|
|
32
|
+
'categories:seo': ['error', {minScore: 0.85}],
|
|
33
|
+
'categories:accessibility': ['error', {minScore: 0.88}]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Translations
|
|
2
|
+
|
|
3
|
+
Most of the files in this folder are generated by `react-intl` **CLI tool**:
|
|
4
|
+
|
|
5
|
+
- `<root>/translations/en-US.json` <- output of _extracting_ the default messages, which you can send to your translators.
|
|
6
|
+
- `<root>/translations/[locale].json` <- the files that your translators make for the other locales
|
|
7
|
+
- `<root>/translations/compiled/[locale].json` <- output of _compiling_ the messages into AST format
|
|
8
|
+
- Compiling helps improve the performance because it allows `react-intl` to skip the parsing step
|
|
9
|
+
|
|
10
|
+
Several **npm scripts** are available to you that make it easier to use the CLI tool. See `package.json` for more details.
|
|
11
|
+
|
|
12
|
+
- To **extract the default messages**, run `npm run extract-default-translations` to have all the default messages extracted into a json file. By default, en-US.json is the file that's generated. If you wish to extract your messages into a different json file, simply update the script by replacing `en-US` with your desired locale.
|
|
13
|
+
- To **compile the translations** from all the locales, run `npm run compile-translations`.
|
|
14
|
+
- To run **both an extract and compile**, run `npm run build-translations`.
|
|
15
|
+
|
|
16
|
+
## Formatting Messages
|
|
17
|
+
|
|
18
|
+
For all the hardcoded translations in your site, write them...
|
|
19
|
+
|
|
20
|
+
- _inline_ in the components, so it’s easier to see where in the page or component that they get used in
|
|
21
|
+
- and in the _default/fallback locale_ (for example, in English)
|
|
22
|
+
|
|
23
|
+
For example, in your React component, you can add formatted messages like `intl.formatMessage({defaultMessage: '...'})` or `<FormattedMessage defaultMessage="..." />`
|
|
24
|
+
|
|
25
|
+
### Adding Message Id
|
|
26
|
+
|
|
27
|
+
At the minimum, only defaultMessage is the required parameter. The message id is optional. If you don’t specify it, the id is auto-generated for you.
|
|
28
|
+
|
|
29
|
+
## Testing with a Pseudo Locale
|
|
30
|
+
|
|
31
|
+
To check whether you’ve wrapped all the hardcoded strings with either `intl.formatMessage()` or `<FormattedMessage />` , there’s a quick way to test that by running `npm run start:pseudolocale`. It runs your local dev server with the locale forced to the pseudo locale.
|
|
32
|
+
|
|
33
|
+
Loading the site in your browser, you can quickly see that those messages that have been formatted would look like this: `[!! Ṕŕíííṿâćććẏ ṔṔṔŏĺíííćẏ !!]`
|
|
34
|
+
|
|
35
|
+
# Localization
|
|
36
|
+
|
|
37
|
+
Since the Retail React App supports **multiple sites** feature, this means each site can have its own localization setup. In each site,
|
|
38
|
+
the default locale, supported locales, and currency settings are defined in a site object in `config/sites.js` under `ll0n`.
|
|
39
|
+
|
|
40
|
+
The locale ids `l10n.supportedLocales[n].id` follow the format supported by OCAPI and Commerce API: `<language code>-<country code>` as defined in this InfoCenter topic: [OCAPI localization 21.8](https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/OCAPI/current/usage/Localization.html).
|
|
41
|
+
|
|
42
|
+
The currency code in `l10n.supportedCurrencies` and `l10n.supportedLocales[n].preferredCurrency` follow the ISO 4217 standard.
|
|
43
|
+
|
|
44
|
+
**Important**: The supported locale settings `l10n.supportedLocales` must match the locale settings for your B2C Commerce instance. For more information about configuring locales on a B2C Commerce instance, see this InfoCenter topic: [Configure Site Locales](https://documentation.b2c.commercecloud.salesforce.com/DOC2/topic/com.demandware.dochelp/content/b2c_commerce/topics/admin/b2c_configuring_site_locales.html).
|
|
45
|
+
|
|
46
|
+
Here’s an example of locale configuration in sites configuration:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// config/sites.js
|
|
50
|
+
modules.exports = [
|
|
51
|
+
{
|
|
52
|
+
id: 'site-id',
|
|
53
|
+
l10n: {
|
|
54
|
+
supportedCurrencies: ['GBP', 'EUR', 'CNY', 'JPY'],
|
|
55
|
+
defaultCurrency: 'GBP',
|
|
56
|
+
supportedLocales: [
|
|
57
|
+
{
|
|
58
|
+
id: 'de-DE',
|
|
59
|
+
preferredCurrency: 'EUR'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'en-GB',
|
|
63
|
+
preferredCurrency: 'GBP'
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'es-MX',
|
|
67
|
+
preferredCurrency: 'MXN'
|
|
68
|
+
},
|
|
69
|
+
// other locales
|
|
70
|
+
],
|
|
71
|
+
defaultLocale: 'en-GB'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## How to Add a New Locale
|
|
78
|
+
|
|
79
|
+
The process for adding a new locale is as follows:
|
|
80
|
+
|
|
81
|
+
1. Create/enable the new locale in Business Manager of your B2C Commerce instance
|
|
82
|
+
2. Enable the locale's currency too in Business Manager
|
|
83
|
+
3. Add the new locale and its currency to your targeted site in `config/sites.js`
|
|
84
|
+
4. If the new locale is also going to be the locale of your inline default messages:
|
|
85
|
+
- Update those default messages to be in that locale's language
|
|
86
|
+
- Run `npm run extract-default-translations` to extract the new translations
|
|
87
|
+
- Send the extracted translations to your translation team
|
|
88
|
+
5. Place the files you receive from your translation team into the `<root>/translations/` folder
|
|
89
|
+
6. Run `npm run compile-translations`
|
|
90
|
+
|
|
91
|
+
## Tips
|
|
92
|
+
|
|
93
|
+
Here are a few useful things to know for developers.
|
|
94
|
+
|
|
95
|
+
### User-Preferred Locales vs. App-Supported Locales
|
|
96
|
+
|
|
97
|
+
How a locale gets chosen depends on whether there’s a match found between 2 sets of locales. On a high level, it looks like this:
|
|
98
|
+
|
|
99
|
+
1. Get the app-supported locales, which are defined in each site object in `config/sites.js` (under `l10n.supportedLocales` of your targeted site).
|
|
100
|
+
2. Get the user-preferred locales, which are what the visitors prefer to see. The developer is responsible for fully implementing them in their own projects within the special `_app` component.
|
|
101
|
+
3. If there’s a match between these 2 sets of locales, then the app would use it as the target locale.
|
|
102
|
+
4. Otherwise, the app would fall back to the locale of the inline `defaultMessage`s.
|
|
103
|
+
|
|
104
|
+
### How to Detect the Active Locale
|
|
105
|
+
|
|
106
|
+
- Within component render, `useLocale` hook is available to you: `const locale = useLocale()`
|
|
107
|
+
- Within a page’s `getProps` you can call utility function `resolveLocaleFromUrl` like this:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
ProductDetail.getProps = async ({res, params, location, api}) => {
|
|
111
|
+
const locale = resolveLocaleFromUrl(`${location.pathname}${location.search}`)
|
|
112
|
+
...
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Dynamic Loading of the Translation Files
|
|
117
|
+
|
|
118
|
+
Using dynamic import, regardless of how many locales the app supports, it would load only one locale at a time.
|
|
119
|
+
|
|
120
|
+
Initially, on app load, the translated messages are part of the server-rendered html. Afterwards on the client side, when dynamically changing the locale, the app would download the JSON file associated with that locale.
|
|
121
|
+
|
|
122
|
+
- Each locale is a separate JSON file in the bundle. And it’s served with a 1-year cache header.
|
|
123
|
+
- When a new bundle is deployed, you must download the JSON files again.
|
|
124
|
+
|
|
125
|
+
### Link Component
|
|
126
|
+
|
|
127
|
+
The generated project comes with its own `Link` component. It automatically inserts the locale in the URLs for you.
|