Skip to content

Conversation

@lariciamota
Copy link
Contributor

@lariciamota lariciamota commented Jan 15, 2026

What's the purpose of this pull request?

This PR implements the logic for the localization binding selector. Merchants need to support multiple language/currency combinations (bindings) with different sales channels. This feature provides the logic layer that enables users to switch between these bindings dynamically.

How it works?

Core Components

1. Hook: useBindingSelector

  • Manages state and orchestrates the binding selection flow
  • Pre-selects current locale and currency from session
  • Provides languages and currencies as Record<string, string> format ready for the selector UI component
  • Handles locale changes with automatic currency validation and adjustment
  • Validates selections before redirecting to the resolved binding URL

2. Utility: buildLanguageOptions

  • Disambiguates languages when multiple locales share the same language name
  • Example: Portuguese appears as "Portuguese (BR)" and "Portuguese (PT)", while unique languages like "English" display without region code

3. Utility: getCurrenciesForLocale

  • Extracts unique currency codes available for a given locale

4. Utility: resolveBinding

  • Resolves the correct binding when multiple bindings exist for the same locale+currency combination
  • Applies isDefault as a tie-breaker for deterministic selection

5. Utility: isValidUrl

  • Validates binding URLs before redirect to prevent errors

Logic Flow

  1. Initial State: Hook pre-selects current locale and currency from session
  2. Language Selection: User selects locale → currencies are filtered to show only available options
  3. Currency Handling:
    • If selected currency is available in new locale → keep it selected
    • If new locale has only one currency → auto-select it
    • If currency is unavailable → clear selection and show available options
  4. Validation: Both locale and currency must be selected, with no errors
  5. Save: Resolves binding, validates URL, and redirects user

How to test it?

Check that the options in the selector match the bindings saved on discovery.config

Examples using the brandless account configuration:

Screenshot 2026-01-15 at 08 15 44 Screenshot 2026-01-15 at 08 15 36

Screen.Recording.2026-01-15.at.08.16.53.mov

Starters Deploy Preview

References

Summary by CodeRabbit

  • New Features

    • Added language and currency selector modal in the navigation bar with customizable labels and descriptions
    • Extended slide-over component to support bottom positioning in addition to left and right
    • Enhanced popover positioning capabilities
  • Style

    • Added styling for the language/currency selector to support responsive desktop and mobile layouts

✏️ Tip: You can customize this high-level summary in your review settings.

@lariciamota lariciamota self-assigned this Jan 15, 2026
@lariciamota lariciamota added the enhancement New feature or request label Jan 15, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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.

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

📝 Walkthrough

Walkthrough

This PR introduces an internationalization selector feature with a new I18nSelector component for language and currency selection. It includes a new useBindingSelector hook for state management, enhances Popover with portal rendering and SlideOver with bottom-side direction support, integrates the selector into Navbar components, adds supporting utilities and type definitions, and provides comprehensive test coverage.

Changes

Cohort / File(s) Summary
Popover Enhancement
packages/components/src/molecules/Popover/Popover.tsx
Added enablePortal prop (default false) and wrapperProps to enable portal rendering into document.body. When enabled, uses fixed positioning without scroll offsets; otherwise uses absolute positioning with standard offset calculations.
SlideOver Enhancement
packages/components/src/organisms/SlideOver/SlideOver.tsx
Expanded Direction type to include 'bottomSide' option, adding support for bottom-slide-over presentations alongside existing left/right directions.
I18nSelector Component
packages/core/src/components/i18n/I18nSelector/I18nSelector.tsx
packages/core/src/components/i18n/I18nSelector/index.ts
packages/core/src/components/i18n/I18nSelector/section.module.scss
New component with desktop (Popover) and mobile (SlideOver) variants, managing language/currency selection with save action, error handling, loading states, and responsive presentations. Includes SCSS module composing styles.
I18nButton Refactoring
packages/core/src/components/ui/I18nButton/I18nButton.tsx
Transformed from minimal icon-only component to stateful selector trigger. Now manages I18nSelector open/closed state, uses useBindingSelector hook, and passes comprehensive props (title, labels, description, save callback) to selector.
Navbar Integration
packages/core/src/components/navigation/Navbar/Navbar.tsx
packages/core/src/components/navigation/NavbarSlider/NavbarSlider.tsx
packages/core/src/components/sections/Navbar/Navbar.tsx
Added i18nSelector prop accepting title, language/currency labels, description, and save label. Navbar passes props to I18nButton (desktop) and NavbarSlider (mobile). NavbarSection maps nested navigation config to component props.
i18n Hook & Utilities
packages/core/src/sdk/i18n/useBindingSelector.ts
packages/core/src/sdk/i18n/bindingSelector.ts
packages/core/src/sdk/i18n/types.ts
New hook managing locale/currency state with session integration, binding resolution, and URL validation. Utilities include: buildLanguageOptions, getCurrenciesForLocale, resolveBinding, isValidUrl. Types define Binding, Locale, and BindingSelectorError.
Index & Configuration
packages/core/src/components/i18n/index.ts
packages/core/src/sdk/i18n/index.ts
packages/core/cms/faststore/sections.json
Public exports for I18nSelector component and useBindingSelector hook/types. CMS configuration adds i18nSelector schema to Navbar with localized field labels and defaults.
Styling
packages/ui/src/components/organisms/I18nSelector/styles.scss
packages/ui/src/components/organisms/SlideOver/styles.scss
packages/ui/src/styles/components.scss
New I18nSelector styles with desktop/mobile variants, responsive layouts, and footer handling. SlideOver styles add bottomSide positioning with height/transform logic. Component imports added to main stylesheet.
Test Coverage
packages/core/test/sdk/i18n/bindingSelector.test.ts
packages/core/test/sdk/i18n/useBindingSelector.test.tsx
Comprehensive vitest suites covering utility functions (language options, currency extraction, binding resolution, URL validation) and end-to-end hook flows with locale/currency switching and binding validation.

Sequence Diagram

sequenceDiagram
    participant User
    participant I18nButton
    participant I18nSelector
    participant useBindingSelector
    participant BindingResolver
    participant Navigation

    User->>I18nButton: Click i18n button
    I18nButton->>I18nSelector: Open selector (Desktop: Popover / Mobile: SlideOver)
    I18nSelector->>useBindingSelector: Read current locale/currency
    useBindingSelector-->>I18nSelector: Return languages, currencies, current selections
    I18nSelector->>User: Display language/currency options

    User->>I18nSelector: Select new locale
    I18nSelector->>useBindingSelector: setLocaleCode(newLocale)
    useBindingSelector->>useBindingSelector: Filter currencies for new locale
    useBindingSelector-->>I18nSelector: Update available currencies

    User->>I18nSelector: Select currency
    I18nSelector->>useBindingSelector: setCurrencyCode(newCurrency)
    useBindingSelector->>useBindingSelector: Validate selection, compute canSave
    useBindingSelector-->>I18nSelector: Enable save button

    User->>I18nSelector: Click save
    I18nSelector->>useBindingSelector: save()
    useBindingSelector->>BindingResolver: resolveBinding(currencyCode)
    BindingResolver->>BindingResolver: Validate URL from binding
    BindingResolver-->>useBindingSelector: Binding with valid URL
    useBindingSelector->>Navigation: Navigate to binding URL
    Navigation-->>User: Page reloads with new locale/currency
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A selector springs to life, so fine,
With languages and currencies to align!
From Navbar to hook, the i18n flows,
Portal, SlideOver—where localization goes!
Popover portals dance, bottomSide does slide,
Global commerce now has nowhere to hide! 🌍✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "feat: Localization Selector logic" accurately summarizes the main change: implementing the binding selector logic for localization/i18n functionality across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jan 15, 2026

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.

@lariciamota lariciamota force-pushed the feat/logic-i18n-selector branch from 631dd81 to fd89b72 Compare January 15, 2026 18:45
@lariciamota lariciamota marked this pull request as ready for review January 16, 2026 14:48
@lariciamota lariciamota requested a review from a team as a code owner January 16, 2026 14:48
@lariciamota lariciamota requested review from gabpaladino, hellofanny, lemagnetic and lucasfp13 and removed request for a team, gabpaladino and lucasfp13 January 16, 2026 14:48
@lariciamota lariciamota changed the title feat: I18n selector logic feat: Localization Selector logic Jan 16, 2026
@lariciamota lariciamota force-pushed the feat/logic-i18n-selector branch from 8bf54f0 to fd89b72 Compare January 16, 2026 15:05
@lariciamota
Copy link
Contributor Author

Renaming PR (from I18nSelector to LocalizationSelector)

Base automatically changed from feat/i18n-selector to feat/multilanguage January 16, 2026 17:06
@renatomaurovtex
Copy link
Contributor

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/components/src/molecules/Popover/Popover.tsx (1)

151-151: Conditional hook call violates Rules of Hooks.

useRef is called conditionally based on the value of ref. React hooks must be called unconditionally and in the same order on every render. If ref changes from null/undefined to a valid ref (or vice versa) between renders, this will cause inconsistent hook ordering.

Proposed fix
-  // Use forwarded ref or internal ref for fallback
-  const popoverRef = ref || useRef<HTMLDivElement>(null)
+  // Internal ref for fallback when no forwarded ref provided
+  const internalRef = useRef<HTMLDivElement>(null)
+  const popoverRef = ref || internalRef
🤖 Fix all issues with AI agents
In `@packages/core/src/components/i18n/I18nSelector/I18nSelector.tsx`:
- Around line 196-199: The selector currently calls onClose() unconditionally in
handleSave which hides any save errors; change handleSave to only close on a
confirmed successful save: have onSave return a success indicator (e.g., boolean
or resolved promise) or propagate errors, then in handleSave await onSave(),
check the returned value or catch errors and set the component's error state
(the same error state used by the error display logic) and only call onClose()
when the save succeeded; if onSave throws, catch and set the error state and do
not call onClose.
🧹 Nitpick comments (7)
packages/core/src/sdk/i18n/bindingSelector.ts (1)

75-83: Consider validating URL scheme to prevent unsafe protocols.

The URL constructor accepts URLs with potentially dangerous schemes like javascript:. Since this is used for redirect validation, consider restricting to safe protocols.

Optional: Restrict to http/https schemes
 export function isValidUrl(url: string): boolean {
   if (!url || url.trim() === '') return false
   try {
-    new URL(url)
-    return true
+    const parsed = new URL(url)
+    return ['http:', 'https:'].includes(parsed.protocol)
   } catch {
     return false
   }
 }
packages/core/test/sdk/i18n/bindingSelector.test.ts (1)

38-46: Edge case: makeLocale assumes simple language-region format.

The split on - may not work correctly for locale codes with scripts (e.g., zh-Hans-CN) or extended formats. Since test data currently uses simple codes, this isn't blocking, but worth noting if test coverage expands.

🔧 Suggested improvement for robustness
 function makeLocale(code: string, languageName: string): Locale {
-  const [languageCode, regionCode] = code.split('-')
+  const parts = code.split('-')
+  const languageCode = parts[0]
+  const regionCode = parts[parts.length - 1] // Last segment is typically region
   return createLocale({
     code,
     languageName,
     languageCode,
     regionCode,
   })
 }
packages/core/src/sdk/i18n/useBindingSelector.ts (2)

13-34: Consider extracting shared types to types.ts.

Currency, Region, and LocalizationConfig are defined locally but relate to the broader i18n type system. If these types are used elsewhere or represent the discovery.config schema, consider exporting them from types.ts for consistency.


131-162: Consider providing user feedback before redirect.

The save() function redirects immediately on success via window.location.href. If the redirect fails or is slow, users have no indication the save was processed. Consider returning a promise or adding a loading state for better UX feedback.

packages/core/test/sdk/i18n/useBindingSelector.test.tsx (1)

1-9: File tests utilities, not the React hook - consider renaming or adding hook tests.

The file is named useBindingSelector.test.tsx (suggesting React component/hook tests) but only imports and tests utility functions from bindingSelector.ts. There are no React Testing Library imports or renderHook calls to test the actual hook behavior.

Consider either:

  1. Renaming to bindingSelectorIntegration.test.ts (since it's integration scenarios for utilities)
  2. Adding actual hook tests using @testing-library/react to test state management, session integration, and side effects
#!/bin/bash
# Check if there are actual hook tests elsewhere or if renderHook is used in the codebase
rg -n "renderHook|@testing-library/react" packages/core/test/
packages/ui/src/components/organisms/I18nSelector/styles.scss (1)

33-36: Consider using flex-end for broader browser compatibility.

While justify-content: end is valid CSS, using flex-end provides better compatibility with older browsers if that's a concern for this project.

🔧 Suggested change
  [data-fs-i18n-selector-actions] {
    display: flex;
-   justify-content: end;
+   justify-content: flex-end;
  }
packages/core/src/components/sections/Navbar/Navbar.tsx (1)

76-82: Make i18nSelector optional to align with schema/default usage.
sections.json doesn’t require this field and you already default to {} during destructuring, so keeping it optional avoids forcing callers to provide it.

♻️ Suggested tweak
-    i18nSelector: {
+    i18nSelector?: {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22c848c and fd89b72.

📒 Files selected for processing (20)
  • packages/components/src/molecules/Popover/Popover.tsx
  • packages/components/src/organisms/SlideOver/SlideOver.tsx
  • packages/core/cms/faststore/sections.json
  • packages/core/src/components/i18n/I18nSelector/I18nSelector.tsx
  • packages/core/src/components/i18n/I18nSelector/index.ts
  • packages/core/src/components/i18n/I18nSelector/section.module.scss
  • packages/core/src/components/i18n/index.ts
  • packages/core/src/components/navigation/Navbar/Navbar.tsx
  • packages/core/src/components/navigation/NavbarSlider/NavbarSlider.tsx
  • packages/core/src/components/sections/Navbar/Navbar.tsx
  • packages/core/src/components/ui/I18nButton/I18nButton.tsx
  • packages/core/src/sdk/i18n/bindingSelector.ts
  • packages/core/src/sdk/i18n/index.ts
  • packages/core/src/sdk/i18n/types.ts
  • packages/core/src/sdk/i18n/useBindingSelector.ts
  • packages/core/test/sdk/i18n/bindingSelector.test.ts
  • packages/core/test/sdk/i18n/useBindingSelector.test.tsx
  • packages/ui/src/components/organisms/I18nSelector/styles.scss
  • packages/ui/src/components/organisms/SlideOver/styles.scss
  • packages/ui/src/styles/components.scss
🧰 Additional context used
🧬 Code graph analysis (6)
packages/core/src/components/navigation/NavbarSlider/NavbarSlider.tsx (2)
packages/core/src/components/navigation/Navbar/Navbar.tsx (1)
  • NavbarProps (39-95)
packages/core/src/components/sections/Navbar/Navbar.tsx (1)
  • NavbarProps (14-94)
packages/components/src/organisms/SlideOver/SlideOver.tsx (1)
packages/components/src/organisms/SlideOver/index.ts (1)
  • Direction (3-3)
packages/core/test/sdk/i18n/bindingSelector.test.ts (2)
packages/core/src/sdk/i18n/types.ts (2)
  • Locale (8-17)
  • Binding (1-6)
packages/core/src/sdk/i18n/bindingSelector.ts (4)
  • buildLanguageOptions (10-30)
  • getCurrenciesForLocale (38-46)
  • resolveBinding (56-67)
  • isValidUrl (75-83)
packages/core/test/sdk/i18n/useBindingSelector.test.tsx (2)
packages/core/src/sdk/i18n/types.ts (1)
  • Locale (8-17)
packages/core/src/sdk/i18n/bindingSelector.ts (4)
  • buildLanguageOptions (10-30)
  • getCurrenciesForLocale (38-46)
  • resolveBinding (56-67)
  • isValidUrl (75-83)
packages/core/src/components/ui/I18nButton/I18nButton.tsx (2)
packages/core/src/sdk/i18n/index.ts (1)
  • useBindingSelector (2-2)
packages/core/src/sdk/i18n/useBindingSelector.ts (1)
  • useBindingSelector (66-177)
packages/core/src/components/i18n/I18nSelector/I18nSelector.tsx (3)
packages/core/src/sdk/i18n/index.ts (1)
  • BindingSelectorError (1-1)
packages/core/src/sdk/i18n/types.ts (1)
  • BindingSelectorError (19-22)
packages/components/src/index.ts (1)
  • SlideOverHeader (385-385)
🔇 Additional comments (43)
packages/components/src/organisms/SlideOver/SlideOver.tsx (1)

7-7: LGTM!

The Direction type expansion to include 'bottomSide' is additive and backward compatible. The component correctly propagates this to the data-fs-slide-over-direction attribute, and the corresponding CSS styles are added in styles.scss to handle the new direction.

packages/core/src/sdk/i18n/types.ts (1)

1-22: LGTM!

The type definitions are well-structured:

  • Binding captures binding configuration cleanly
  • Locale has comprehensive locale metadata with appropriate textDirection constraint
  • BindingSelectorError uses a discriminated union pattern, making error handling type-safe and exhaustive
packages/ui/src/components/organisms/SlideOver/styles.scss (1)

92-111: LGTM!

The bottomSide variant implementation is correct:

  • Positioning anchors the panel to the bottom with full width
  • translateY(100%) / translateY(0) transitions provide the slide-up/down effect
  • Max-height constraints for full (100vh) and partial (80vh) sizes are appropriate

Note: This block uses physical properties (top, right, bottom, left) while leftSide/rightSide use logical properties (inset-inline-start/end). This is acceptable since vertical positioning is direction-agnostic in RTL layouts.

packages/components/src/molecules/Popover/Popover.tsx (2)

96-127: LGTM!

The position calculation correctly differentiates between portal and non-portal modes:

  • Portal mode uses raw viewport coordinates (fixed positioning)
  • Non-portal mode adds scroll offsets (absolute positioning)

233-240: LGTM!

The conditional rendering approach is clean—portal mode wraps the element and renders via createPortal, while inline mode returns the element directly.

packages/core/src/sdk/i18n/bindingSelector.ts (2)

10-30: LGTM!

The disambiguation logic correctly identifies duplicate language names and appends the region code only when necessary. This produces clean labels like "Portuguese (BR)" vs "Portuguese (PT)" while keeping unique languages simple.


56-67: LGTM!

The binding resolution logic handles all cases correctly:

  • No matches → null
  • Single match → return it
  • Multiple matches → prefer isDefault, fallback to first

The nullish coalescing (?? matches[0]) ensures a deterministic result even if no binding has isDefault: true.

packages/core/test/sdk/i18n/bindingSelector.test.ts (5)

1-46: LGTM! Well-structured test helpers.

The helper functions provide good reusability and sensible defaults for building test fixtures.


48-93: LGTM! Good coverage for language options disambiguation.

Tests cover unique names, duplicated names requiring disambiguation, mixed scenarios, and empty input.


95-135: LGTM! Data-driven tests with good edge case coverage.

Using testCases.forEach pattern keeps tests DRY while covering deduplication, single bindings, empty arrays, and insertion order preservation.


137-220: LGTM! Thorough tests for binding resolution logic.

Tests cover: no match, single match, isDefault tie-breaker, fallback to first match, empty array, and multiple currencies with defaults. The factory pattern for mock bindings is clean.


222-246: LGTM! URL validation tests cover key scenarios.

Testing valid URLs (with paths, query params, localhost), empty/whitespace, invalid formats, and null-like values provides solid coverage.

packages/core/src/sdk/i18n/useBindingSelector.ts (5)

1-11: LGTM! Clean imports with appropriate type-only imports.


36-58: LGTM! Well-documented return type interface.

JSDoc comments clearly describe each property and action. The interface provides a clean contract for consumers.


96-122: LGTM! Locale change handler with proper currency adjustment logic.

The logic correctly:

  1. Clears errors on selection
  2. Checks if current currency is available in new locale
  3. Auto-selects if only one currency exists
  4. Clears selection otherwise

164-164: Potential stale error in canSave computation.

canSave is computed inline but depends on error state. If setLocaleCode or setCurrencyCode is called and clears the error, the component will re-render with updated canSave. This is correct, but ensure the UI properly reflects the derived state on each render.


70-77: No syncing with session updates after mount—clarify if intentional.

The useState initializers capture session values only once at mount via lazy initialization. If currentLocale or currentCurrency change in the session afterward, the hook state won't update. The code structure suggests this is intentional (user selections in the selector override session defaults), but there's no useEffect or documentation confirming this design. Verify whether:

  1. Session updates during the selector lifetime should propagate to UI state, or
  2. The current behavior (selections override and persist until save/redirect) is the intended pattern.
packages/core/test/sdk/i18n/useBindingSelector.test.tsx (6)

11-93: LGTM! Comprehensive mock data covering diverse scenarios.

The mockLocales fixture includes:

  • Languages with disambiguation needs (pt-BR, pt-PT)
  • Single and multiple currency bindings
  • Multiple bindings for same currency with isDefault tie-breaker (fr-FR)

95-119: LGTM! Language options tests validate disambiguation and output format.


121-139: LGTM! Currency filtering tests cover expected scenarios.


141-169: LGTM! Binding resolution tests verify tie-breaker logic.


171-180: LGTM! URL validation ensures all mock bindings are valid.


182-218: LGTM! Flow simulations demonstrate realistic user journeys.

These end-to-end scenarios provide good documentation of expected behavior through tests.

packages/ui/src/styles/components.scss (1)

97-97: LGTM! Import follows existing conventions.

The I18nSelector styles import is correctly placed in the Organisms section, maintaining alphabetical proximity with other components.

packages/core/src/sdk/i18n/index.ts (1)

1-4: LGTM! Clean barrel exports with proper type-only syntax.

The utility functions (buildLanguageOptions, getCurrenciesForLocale, resolveBinding, isValidUrl) are kept as internal implementation details in bindingSelector.ts and not exported from the public API. This is correct—they're used only internally by the useBindingSelector hook and should not be directly imported elsewhere.

packages/core/src/components/i18n/index.ts (1)

1-1: LGTM!

Clean barrel export that properly exposes the I18nSelector component through the i18n module's public API.

packages/core/src/components/i18n/I18nSelector/index.ts (1)

1-1: LGTM!

Standard re-export pattern for the component folder.

packages/core/src/components/i18n/I18nSelector/section.module.scss (1)

1-16: LGTM!

Well-organized style composition separating desktop, mobile, and common styles. The scoped @import pattern provides clear context for which styles apply to each variant.

packages/ui/src/components/organisms/I18nSelector/styles.scss (2)

1-37: Well-structured base styles.

Good use of CSS custom properties for theming and data attributes for component styling. The hidden indicators/headers (lines 27-31) provide clean I18nSelector presentation inside overlays.


39-67: Mobile variant styles look good.

Properly extends base styles with mobile-specific overrides for full-width elements and adjusted padding/typography.

packages/core/src/components/i18n/I18nSelector/I18nSelector.tsx (6)

17-45: Well-documented props interface.

Clear JSDoc comments explaining each prop's purpose and expected format.


47-109: Comprehensive props interface for I18nSelector.

Good documentation coverage and alignment with the useBindingSelector hook's API as described in the PR objectives.


111-156: Clean presentational component.

The I18nSelectorContent properly renders the form fields and conditionally shows the save button. Good use of the disabled prop on the currency select when no currencies are available.


158-172: Good error message helper.

Covers all BindingSelectorError types with user-friendly messages. The default case provides defensive handling for any future error types.


217-251: Desktop Popover variant is well-implemented.

Good use of enablePortal for proper stacking context and appropriate null-coalescing for locale/currency codes.


253-291: Mobile SlideOver variant looks good.

Clean implementation with proper fade transitions and footer button placement. The direction="bottomSide" creates a bottom sheet UX appropriate for mobile.

packages/core/src/components/sections/Navbar/Navbar.tsx (1)

114-120: Clean prop threading into Navbar.
The selector labels are passed through consistently without impacting existing behavior.

Also applies to: 142-148

packages/core/src/components/navigation/NavbarSlider/NavbarSlider.tsx (1)

18-26: Props and render wiring for the selector look consistent.
Good pass-through of configuration to the I18nButton.

Also applies to: 33-34, 100-108

packages/core/cms/faststore/sections.json (1)

454-484: Schema addition for i18nSelector is well-formed.
Defaults and labels read clearly.

packages/core/src/components/navigation/Navbar/Navbar.tsx (2)

73-82: i18nSelector prop surface is clear and optional.


106-107: Selector props are passed through cleanly to desktop and slider flows.

Also applies to: 214-222, 257-257

packages/core/src/components/ui/I18nButton/I18nButton.tsx (2)

1-38: Hook integration and prop surface look solid.
Nice consolidation around useBindingSelector.


40-90: Selector rendering and state wiring are clear.
Good use of the trigger ref and callback pass-throughs.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #3177

coderabbitai bot added a commit that referenced this pull request Jan 16, 2026
Docstrings generation was requested by @renatomaurovtex.

* #3175 (comment)

The following files were modified:

* `packages/core/src/components/i18n/I18nSelector/I18nSelector.tsx`
* `packages/core/src/components/navigation/Navbar/Navbar.tsx`
* `packages/core/src/components/navigation/NavbarSlider/NavbarSlider.tsx`
* `packages/core/src/components/sections/Navbar/Navbar.tsx`
* `packages/core/src/sdk/i18n/bindingSelector.ts`
* `packages/core/src/sdk/i18n/useBindingSelector.ts`
@hellofanny
Copy link
Contributor

hellofanny commented Jan 20, 2026

I found a little be strange to update/display the selected Language in the Localization Button even before really setting the language (save and redirect)
I think we can keep displaying the current session locale / currency until the changes. Not sure if we aligned differently with the design team 🤔

Screen.Recording.2026-01-19.at.23.29.22.mov

@lariciamota lariciamota force-pushed the feat/logic-i18n-selector branch 2 times, most recently from 13ff950 to bf4ba8f Compare January 20, 2026 11:25
@lariciamota
Copy link
Contributor Author

I found a little be strange to update/display the selected Language in the Localization Button even before really setting the language (save and redirect) I think we can keep displaying the current session locale / currency until the changes. Not sure if we aligned differently with the design team 🤔

Totally! I've confirmed with Vanessinha and we should display the session locale/currency indeed. Fixed it! Thanks!

@lariciamota lariciamota force-pushed the feat/logic-i18n-selector branch from 4d934ef to fd60a5a Compare January 20, 2026 14:42
@lariciamota lariciamota merged commit 7a976d2 into feat/multilanguage Jan 20, 2026
5 of 6 checks passed
@lariciamota lariciamota deleted the feat/logic-i18n-selector branch January 20, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants