Skip to content

feat(core): localized product URLs, breadcrumbs PDP and PLPs#3402

Draft
hellofanny wants to merge 1 commit into
devfrom
feat/localized-slugs-links
Draft

feat(core): localized product URLs, breadcrumbs PDP and PLPs#3402
hellofanny wants to merge 1 commit into
devfrom
feat/localized-slugs-links

Conversation

@hellofanny

Copy link
Copy Markdown
Contributor

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9e1d1b5b-3de0-454b-927f-5e37696bdb70

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/localized-slugs-links

Comment @coderabbitai help to get the list of available commands and usage tips.

@codesandbox-ci

codesandbox-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

…3352)

## Summary

Implements localized product links for FastStore stores with
localization.enabled: true (PDP only — PLP localized slugs are handled
separately).

**it-IT**
<img width="1907" height="1001" alt="image"
src="https://github.com/user-attachments/assets/b78831db-edbd-4db3-96bb-0c67b4b6c20b"
/>

**pt-BR**
<img width="1918" height="992" alt="image"
src="https://github.com/user-attachments/assets/f357c607-a37d-41e2-b13a-abf25de2629d"
/>


### Problem

FastStore stores with localization enabled had three major issues on the
PDP:
1. Localized product URLs (e.g. `/it-IT/adidas-polo-uomo-65/p`) returned
404 because the `Query.product` resolver's `startsWith` guard rejected
slugs whose prefix didn't match the Intelligent Search `linkText`
(always in the default locale).
2. Breadcrumb items were rendered as non-clickable `<span>` elements and
`BreadcrumbJsonLd` was suppressed entirely.
3. The `LocalizationSelector` had no localized product URL to navigate
to when the shopper switched locale.
4. After landing on a 404 from a locale switch, the LocalizationSelector
lost the product context and couldn't recover the correct localized URL
— and the 404 page showed the bare asPath instead of the full
locale-prefixed URL.

### Changes

@faststore/api

- New clients/catalog/ client — uses the public
catalog-dataplane/product/{id} endpoint (Accept-Language header, no
AppKey/AppToken required) to fetch localized product data (linkId,
category.fullPathUriName) per locale
- Query.product resolver: when startsWith fails and localization is
enabled, validates the slug prefix against the - - Catalog Dataplane
linkId for the current locale before rejecting
- New StoreProduct.otherLocales: [StoreProductLocale!] field — fires
Promise.all over all configured locales to build localized slug entries;
zero overhead for non-localized stores
- StoreProduct.breadcrumbList resolver: now async; uses
category.fullPathUriName from the Catalog Dataplane for localized
category URL paths and linkId for the product URL; falls back to
slugify(IS name) when no translation exists
- productTranslationsCache in GraphqlContext.storage — request-scoped
cache keyed by productId:locale shared across all three resolvers to
avoid duplicate API calls

@faststore/core

- New `LocalizedProductContext` — React context that provides
otherLocales from the PDP GraphQL response to - any component in the
tree (including global components like LocalizationButton)
- `useLocalizedProduct_unstable` exported from experimental/index.ts for
store customization
- `LocalizationButton` / `useBindingSelector`: uses otherLocales to
redirect to the correct localized product URL on locale switch; falls
back to the defaultLocale slug when no translation exists for the target
locale
- `useBindingSelector`: persists otherLocales to sessionStorage keyed by
SKU id (fs:otherLocales:{skuId}) so the locale selector can recover the
correct product URL even after the user lands on a 404 (where the page
no longer provides otherLocales)
- `Breadcrumb.tsx`: removed localization.enabled workaround — always
renders <Link> now that localized URLs are available
-`p.tsx`: restored BreadcrumbJsonLd for all locales + added hreflang
alternate tags via NextSeo.additionalLinkTags (including x-default
pointing to the root store URL)
- `EmptyState`: the fromUrl shown on the 404 page now includes the
active Next.js locale prefix (e.g. /it-IT/...) so shoppers see the full
URL they attempted to visit

### Architecture note

The Catalog Dataplane is called once per product+locale combination. For
otherLocales (all locales) and breadcrumbList (current locale only),
results are shared via productTranslationsCache. A future optimization —
replacing the Promise.all with a single "all-locales" endpoint from the
Catalog team — would be a contained 2-file change with no behavior
impact.

The sessionStorage persistence in `useBindingSelector` uses a
fs:otherLocales:{skuId} key and is intentionally session-scoped (cleared
on tab close). It is a best-effort fallback; the locale selector always
prefers live otherLocales from context when available.

## Test plan

try using `brandless` acc

- [ ] Visit a localized PDP (e.g. `/it-IT/{localized-slug}-{skuId}/p`) —
page renders correctly
eg. /adidas-mens-performance-polo-blast-blue-65/p -> switch to it-IT
locale! You will be able to see the slug localized.
- [ ] Visit a non-localized locale PDP (e.g.
`/pt-BR/{default-slug}-{skuId}/p`) — page renders correctly (fallback
path)
eg. select en-CA
- [ ] PDP breadcrumb items are clickable `<Link>` elements with
localized category URLs
- [ ] 2-level category hierarchy breadcrumb builds correct intermediate
paths
- [ ] `LocalizationSelector` navigates to the correct localized product
URL for each locale
- [ ] `LocalizationSelector` falls back to the default locale slug for
locales without a translation
- [ ] `hreflang` tags appear in `<head>` for all configured locales +
`x-default` (lists only the `availableLinkIds`)
<img width="1086" height="181" alt="Screenshot 2026-06-11 at 16 33 23"
src="https://github.com/user-attachments/assets/e1dc0ed0-3332-492b-9a1d-84a33c3a1eb4"
/>

<img width="498" height="178" alt="Screenshot 2026-06-11 at 16 37 36"
src="https://github.com/user-attachments/assets/6f52bb39-9211-4ece-8462-14e0841d6115"
/>

- [ ] `BreadcrumbJsonLd` appears in page source for all locales
- [ ] Non-localized stores (`localization.enabled: false`) — no
regression, no extra API calls
- [ ] Switch locale on a PDP → land on a 404 → LocalizationSelector
still shows/navigates to correct localized URLs for all locales
- [ ] 404 page fromUrl displays the full locale-prefixed path (e.g.
/it-IT/some-product/p)


[Spec file for more
information](vtex/faststore-dx-spec-kit#15)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **New Features**
* Product pages now expose `otherLocales` via a dedicated localization
context/provider.
  * Product pages generate multi-locale SEO `hreflang` alternate links.
* Added localized VTEX catalog support to fetch locale-specific
product/category details.

* **Improvements**
* Breadcrumbs now use localized category/product path segments when
available and consistently render as links.
* Locale-aware product slug validation and PDP redirects that use cached
or persisted `otherLocales`.
  * Added request-scoped caching for localized product lookups.

* **Tests**
* Expanded coverage for PDP locale parsing plus `otherLocales`
persistence/recovery behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@hellofanny hellofanny force-pushed the feat/localized-slugs-links branch from 92bc71f to ae5b6fe Compare June 19, 2026 22:55
@pkg-pr-new

pkg-pr-new Bot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@faststore/api

npm i https://pkg.pr.new/vtex/faststore/@faststore/api@ae5b6fe

@faststore/cli

npm i https://pkg.pr.new/vtex/faststore/@faststore/cli@ae5b6fe

@faststore/components

npm i https://pkg.pr.new/vtex/faststore/@faststore/components@ae5b6fe

@faststore/core

npm i https://pkg.pr.new/vtex/faststore/@faststore/core@ae5b6fe

@faststore/diagnostics

npm i https://pkg.pr.new/vtex/faststore/@faststore/diagnostics@ae5b6fe

@faststore/lighthouse

npm i https://pkg.pr.new/vtex/faststore/@faststore/lighthouse@ae5b6fe

@faststore/sdk

npm i https://pkg.pr.new/vtex/faststore/@faststore/sdk@ae5b6fe

@faststore/ui

npm i https://pkg.pr.new/vtex/faststore/@faststore/ui@ae5b6fe

commit: ae5b6fe

@sonar-workflows

Copy link
Copy Markdown

Failed Quality Gate failed

  • 1 New Issues (is greater than 0)
  • 52.90% Coverage on New Code (is less than 80.00%)

Project ID: vtex_faststore_f0a862d5-9557-49f9-8d09-de40caa76622

View in SonarQube

@hellofanny hellofanny changed the title feat(core): localized product URLs, breadcrumbs and hreflang for PDP … feat(core): localized product URLs, breadcrumbs PDP and PLPs Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant