Skip to content

Added a responsive, functional language switcher button in navbar#327

Open
reach2saksham wants to merge 5 commits intoAOSSIE-Org:new-designfrom
reach2saksham:feat/language-switch-button
Open

Added a responsive, functional language switcher button in navbar#327
reach2saksham wants to merge 5 commits intoAOSSIE-Org:new-designfrom
reach2saksham:feat/language-switch-button

Conversation

@reach2saksham
Copy link

@reach2saksham reach2saksham commented Mar 8, 2026

Description

Adds an English / Hindi language switcher to the navbar.

Fixes #324

Type of change

components/layout/Navbar.tsx

New: LanguageDropdown component

  • Self-contained dropdown that reads the current locale from usePathname() and navigates to the equivalent route in the selected language via useRouter().
  • Supports two render modes controlled by the isMobile prop:
    • Desktop — compact pill button showing a globe icon + two-letter code (EN / HI) with a popover menu anchored to the right.
    • Mobile — full-width button showing the language's display name (English / हिन्दी) with an inline dropdown.
  • Active locale is indicated with a checkmark; inactive options use muted text.
  • Chevron rotates 180° on open.
  • Closes on outside click via a mousedown listener attached to a wrapping ref.
  • Dropdown panels carry an explicit backgroundColor: var(--background, white) inline style to prevent the parent navbar's backdrop-blur from bleeding through and making the panel transparent.

New: inline SVG icon helpers

Three tiny, prop-typed SVG components added at the module level to keep JSX readable: GlobeIcon, ChevronIcon, CheckIcon.

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • UI/UX update (design changes, interface improvements)

How Has This Been Tested?

  1. Desktop: switching language: open the site at /en, click the EN globe button in the navbar, select हिन्दी. URL should change to /hi/.... Refresh, the dropdown should show HI as active with a checkmark.
  2. Mobile: language switcher: open the mobile menu, tap the language button. The dropdown panel should have a solid background (no bleed-through from the page behind it), and selecting a language should navigate correctly.
  3. Theme: toggle between light and dark mode; the dropdown background should match the page background in both themes.

Notes

  • English is the default locale. If no recognised locale prefix is found in the pathname, switchLocale prepends the selected code rather than replacing a non-existent segment.
  • The existing (commented-out) <LanguageSwitcher /> import and usages have been left in place as comments so they can be removed or re-enabled independently.
  • No new dependencies were introduced. useRouter and usePathname are already available via next/navigation.

Please include screenshots below if applicable:

Recording.2026-03-16.172458.mp4

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

Summary by CodeRabbit

  • New Features
    • Redesigned language selection dropdown with dedicated mobile and desktop layouts for improved locale switching (EN/HI).
    • Added language-related icons and a languages list for consistent UI.
    • Preserves URL hash when switching locales.
    • Improved interactions: outside-click closes menu, auto-focus first item on open, and keyboard navigation (Esc, ArrowUp/Down).

@reach2saksham
Copy link
Author

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 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.

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 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.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a3652a3-d3f6-43af-9dea-89aa0b618fa6

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
📝 Walkthrough

Walkthrough

Replaced the previous dynamic language switcher with an in-file LanguageDropdown inside Navbar.tsx. Adds LANGUAGES and icon components, locale-switching via Next.js router.replace (preserving hash), outside-click and keyboard/focus handling, and integrates the dropdown into desktop and mobile nav flows.

Changes

Cohort / File(s) Summary
Language Dropdown & Navbar integration
src/components/layout/Navbar.tsx
Added an in-file LanguageDropdown (desktop + mobile variants), LANGUAGES constant, small icon components (GlobeIcon, ChevronIcon, CheckIcon), locale switching via router.replace preserving hash, outside-click detection, focus management and keyboard navigation (Escape, ArrowUp/Down). Updated Navbar to render the dropdown in desktop actions and mobile submenu. Imports expanded (useRef, useRouter, usePathname, useSearchParams, useLocale). Minor layout/behavior adjustments to accommodate the new menu.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Navbar
    participant Router
    participant Document

    User->>Navbar: Clicks language button
    activate Navbar
    Navbar->>Document: Attach outside-click listener
    Navbar->>Navbar: Open menu, focus first item
    User->>Navbar: ArrowDown / ArrowUp or selects language
    Navbar->>Router: router.replace(newLocalePath, { locale })
    Router-->>Navbar: Navigation complete
    User->>Document: Click outside
    Document-->>Navbar: Outside click detected
    Navbar->>Navbar: Close menu, remove listener
    deactivate Navbar
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement, new-design

Suggested reviewers

  • M4dhav

Poem

🐰 A dropdown hops into the Navbar bright,
Globe on one paw, chevron on the right,
Hindi and English, a gentle swap,
Keys and clicks, the menu pops,
The rabbit twirls — locale delight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a responsive, functional language switcher button to the navbar, which directly aligns with the changeset.
Linked Issues check ✅ Passed The pull request implements all core requirements from issue #324: a language switcher in the navbar supporting en/hi, with responsive design for mobile/desktop, visual language indicators (globe icon, checkmark), and a functional dropdown.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the language switcher component in the navbar. No unrelated modifications to other files or functionality were introduced.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

Migrating from UI to YAML configuration.

Use the @coderabbitai configuration command in a PR comment to get a dump of all your UI settings in YAML format. You can then edit this YAML file and upload it to the root of your repository to configure CodeRabbit programmatically.

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

Added a LanguageDropdown component to the Navbar enabling users to switch between English and Hindi. The component infers the current language from the URL pathname, handles dropdown state management, and rewrites the URL path when a language is selected.

Changes

Cohort / File(s) Summary
Language Dropdown Feature
src/components/layout/Navbar.tsx
Introduced LanguageDropdown component with locale inference from pathname, dropdown state handling, and URL path rewriting logic. Added icon helpers (GlobeIcon, ChevronIcon, CheckIcon) and LANGUAGES constant. Integrated dropdown into both desktop (right-aligned actions) and mobile (inside mobile menu) navbar sections.

Sequence Diagram

sequenceDiagram
    actor User
    participant Navbar
    participant LanguageDropdown
    participant Router
    participant Browser

    User->>LanguageDropdown: Click language button
    LanguageDropdown->>LanguageDropdown: Toggle dropdown open state
    LanguageDropdown->>Navbar: Render language options
    User->>LanguageDropdown: Select new language (e.g., Hindi)
    LanguageDropdown->>Router: useRouter().push(new path with 'hi' locale)
    Router->>Browser: Rewrite URL pathname segment
    Browser->>Navbar: Reload with new locale
    LanguageDropdown->>LanguageDropdown: Infer current language from pathname
    LanguageDropdown->>Navbar: Render with checkmark on selected language
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

new-design, enhancement

Suggested reviewers

  • M4dhav

Poem

🐰 A button soft appears so fine,
With languages that intertwine,
From English words to Hindi speech,
With one small click, all locales reach!
The rabbit hops with joy today—
Language barriers fade away! 🌍

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a responsive, functional language switcher button to the navbar, which is the primary focus of the changeset.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #324: adds a language dropdown for English/Hindi selection in the navbar, restores i18n switching functionality, supports responsive design, and includes dark mode support.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the language switcher feature; no out-of-scope modifications detected beyond the stated objectives.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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: 3

🧹 Nitpick comments (3)
src/components/layout/Navbar.tsx (3)

125-178: Consider extracting icons to a shared module.

These icon components are well-implemented. If similar icons are needed elsewhere in the codebase, consider moving them to a shared components/icons module for reuse. This is optional and can be deferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/Navbar.tsx` around lines 125 - 178, Extract the three
inline icon components (GlobeIcon, ChevronIcon, CheckIcon) into a shared icons
module (e.g., components/icons), export them from that module, and replace the
definitions in Navbar.tsx with imports of those named exports; ensure the
exported components keep the same props and className behaviors (ChevronIcon({
open }: { open: boolean })) so existing usages and typings in Navbar remain
unchanged.

69-86: Add proper ARIA roles for listbox semantics.

The button declares aria-haspopup="listbox", but the dropdown container lacks role="listbox" and the options lack role="option" with aria-selected. This incomplete pattern may confuse assistive technologies.

Proposed fix for mobile dropdown (apply similar changes to desktop)
-          <div className="absolute left-0 right-0 mt-2 rounded-2xl border border-default bg-surface shadow-lg z-50 overflow-hidden animate-in fade-in slide-in-from-top-2 duration-150" style={{ backgroundColor: 'var(--background, white)' }}>
+          <div role="listbox" aria-label="Select language" className="absolute left-0 right-0 mt-2 rounded-2xl border border-default bg-surface shadow-lg z-50 overflow-hidden animate-in fade-in slide-in-from-top-2 duration-150" style={{ backgroundColor: 'var(--background, white)' }}>
             {LANGUAGES.map((lang) => (
               <button
                 key={lang.code}
                 onClick={() => switchLocale(lang.code)}
+                role="option"
+                aria-selected={lang.code === currentLocale}
                 className={`flex items-center justify-between w-full px-4 py-3 text-sm font-medium transition-colors hover:bg-(--hover-background) ${
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/Navbar.tsx` around lines 69 - 86, The dropdown lacks
proper listbox semantics: when rendering the language menu (the block controlled
by open that maps LANGUAGES) add role="listbox" and an accessible label
(aria-label or aria-labelledby) to the container, and on each language button
(the mapped element using key={lang.code}, onClick={() =>
switchLocale(lang.code)}) replace or augment with role="option" and include
aria-selected={lang.code === currentLocale}; keep the visual CheckIcon but
ensure the selected option reflects aria-selected, and ensure the trigger button
that sets open retains aria-haspopup="listbox" and aria-expanded tied to open
for full assistive support.

14-17: Import LANGUAGES from the canonical source instead of duplicating.

The codebase already has a LANGUAGES configuration in src/config/languages.ts. Duplicating this creates a maintenance risk—if locales are added or modified, both definitions must be kept in sync.

Consider extending the canonical type if you need the short field, or derive it from the existing code:

Proposed fix
-const LANGUAGES = [
-  { code: "en", label: "English", short: "EN" },
-  { code: "hi", label: "हिन्दी", short: "HI" },
-];
+import { LANGUAGES } from "@/config/languages";

Then derive short inline where needed:

<span>{current.code.toUpperCase()}</span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/Navbar.tsx` around lines 14 - 17, Replace the
duplicated LANGUAGES array in Navbar.tsx with an import of the canonical
LANGUAGES from src/config/languages (keep the constant name LANGUAGES to
minimize changes) and remove the local definition; if you need a short label,
either extend the canonical language type where it's defined or compute the
short value in the component (e.g., derive from language.code by uppercasing
when rendering, e.g., using current.code.toUpperCase()) so the single source of
truth remains the config LANGUAGES and the Navbar only derives presentation
values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/layout/Navbar.tsx`:
- Line 7: Navbar.tsx currently imports useRouter and usePathname from
next/navigation which bypasses the locale-aware wrappers; update the import to
use the locale-aware hooks exported from "@/i18n/navigation" instead (replace
the direct next/navigation import for useRouter and usePathname), ensuring
Navbar uses the same locale-aware routing as LanguageSwitcher.tsx so locale
switching works correctly.
- Around line 10-12: Remove the dead dynamic import for LanguageSwitcher: delete
the const LanguageSwitcher = dynamic(() => import("../ui/LanguageSwitcher"), {
ssr: false }) declaration (and any unused references to LanguageSwitcher) since
LanguageDropdown now handles language switching; ensure LanguageDropdown remains
and no other code references LanguageSwitcher before committing.
- Around line 41-51: The switchLocale function currently mutates the pathname
segments (LANGUAGES, switchLocale, pathname) which is fragile; replace that
logic with the locale-aware router.replace call used in LanguageSwitcher: call
the locale-aware useRouter's router.replace(pathname, { locale: code })
(preserving query/hash) instead of manually splicing segments, then call
setOpen(false); remove the segment manipulation code and ensure the file uses
the same locale-aware useRouter as LanguageSwitcher.

---

Nitpick comments:
In `@src/components/layout/Navbar.tsx`:
- Around line 125-178: Extract the three inline icon components (GlobeIcon,
ChevronIcon, CheckIcon) into a shared icons module (e.g., components/icons),
export them from that module, and replace the definitions in Navbar.tsx with
imports of those named exports; ensure the exported components keep the same
props and className behaviors (ChevronIcon({ open }: { open: boolean })) so
existing usages and typings in Navbar remain unchanged.
- Around line 69-86: The dropdown lacks proper listbox semantics: when rendering
the language menu (the block controlled by open that maps LANGUAGES) add
role="listbox" and an accessible label (aria-label or aria-labelledby) to the
container, and on each language button (the mapped element using
key={lang.code}, onClick={() => switchLocale(lang.code)}) replace or augment
with role="option" and include aria-selected={lang.code === currentLocale}; keep
the visual CheckIcon but ensure the selected option reflects aria-selected, and
ensure the trigger button that sets open retains aria-haspopup="listbox" and
aria-expanded tied to open for full assistive support.
- Around line 14-17: Replace the duplicated LANGUAGES array in Navbar.tsx with
an import of the canonical LANGUAGES from src/config/languages (keep the
constant name LANGUAGES to minimize changes) and remove the local definition; if
you need a short label, either extend the canonical language type where it's
defined or compute the short value in the component (e.g., derive from
language.code by uppercasing when rendering, e.g., using
current.code.toUpperCase()) so the single source of truth remains the config
LANGUAGES and the Navbar only derives presentation values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e14c647-8802-4af9-bc27-a3f5719d6136

📥 Commits

Reviewing files that changed from the base of the PR and between f3df55f and a997868.

📒 Files selected for processing (1)
  • src/components/layout/Navbar.tsx

Comment on lines 10 to 12
const LanguageSwitcher = dynamic(() => import("../ui/LanguageSwitcher"), {
ssr: false,
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused LanguageSwitcher dynamic import.

LanguageSwitcher is imported but never used in this file since LanguageDropdown now handles language switching. This is dead code.

Proposed fix
-import dynamic from "next/dynamic";
-
-const LanguageSwitcher = dynamic(() => import("../ui/LanguageSwitcher"), {
-  ssr: false,
-});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/Navbar.tsx` around lines 10 - 12, Remove the dead
dynamic import for LanguageSwitcher: delete the const LanguageSwitcher =
dynamic(() => import("../ui/LanguageSwitcher"), { ssr: false }) declaration (and
any unused references to LanguageSwitcher) since LanguageDropdown now handles
language switching; ensure LanguageDropdown remains and no other code references
LanguageSwitcher before committing.

@reach2saksham
Copy link
Author

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 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: 2

🧹 Nitpick comments (1)
src/components/layout/Navbar.tsx (1)

315-320: Expose the mobile menu state to assistive tech.

The hamburger button still has only a static label. Adding aria-expanded and aria-controls would make the open/closed state of the mobile panel discoverable.

Suggested change
-        <button
+        <button
           className="p-1.5 text-primary hover:bg-(--hover-background) rounded-lg transition-colors"
           onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
           aria-label="Toggle menu"
+          aria-expanded={isMobileMenuOpen}
+          aria-controls="navbar-mobile-menu"
         >
@@
-        <div className="lg:hidden border-t border-default bg-(--background-secondary) px-4 sm:px-6 py-4 shadow-xl animate-in slide-in-from-top-5 rounded-b-3xl">
+        <div id="navbar-mobile-menu" className="lg:hidden border-t border-default bg-(--background-secondary) px-4 sm:px-6 py-4 shadow-xl animate-in slide-in-from-top-5 rounded-b-3xl">

Also applies to: 343-345

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/Navbar.tsx` around lines 315 - 320, The mobile menu
toggle button in Navbar.tsx should expose its state to assistive tech: update
the button (where setIsMobileMenuOpen and isMobileMenuOpen are used) to include
aria-expanded={isMobileMenuOpen} and aria-controls referencing the id of the
mobile panel, and ensure the mobile panel element (the collapsible div rendered
for mobile) has that matching id; apply the same attributes for the secondary
button instance noted around lines 343-345 to keep both toggles accessible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/layout/Navbar.tsx`:
- Around line 42-47: The trigger buttons in Navbar use aria-haspopup="listbox"
but the popup panels are plain divs of buttons; change the interaction to a
menu-button pattern: update the triggers (the button using setOpen and
aria-expanded={open}) to use aria-haspopup="menu" and ensure aria-controls
references the popup id, then mark the popup container (the div rendered when
open) with role="menu" and each child button with role="menuitem" (and add
tabindex or aria-disabled as needed); keep using the existing setOpen and open
state logic but ensure keyboard behavior and focus management follow a menu
pattern (focus first item on open or manage Arrow keys) so screen readers
receive the correct menu semantics instead of listbox semantics.
- Around line 17-18: The locale switch currently uses usePathname() and calls
router.replace(pathname, { locale: code }) which drops query string and hash;
update the Locale change logic in Navbar.tsx to read search params via
useSearchParams(), build a query object from searchParams.entries(), capture the
hash via window.location.hash (guarded for SSR), then call router.replace with a
location object ({ pathname, query }) and the locale option, and finally
re-append the hash if present so anchors and filters are preserved; adjust
references around usePathname, useSearchParams, useLocale, pathname,
currentLocale and the router.replace call.

---

Nitpick comments:
In `@src/components/layout/Navbar.tsx`:
- Around line 315-320: The mobile menu toggle button in Navbar.tsx should expose
its state to assistive tech: update the button (where setIsMobileMenuOpen and
isMobileMenuOpen are used) to include aria-expanded={isMobileMenuOpen} and
aria-controls referencing the id of the mobile panel, and ensure the mobile
panel element (the collapsible div rendered for mobile) has that matching id;
apply the same attributes for the secondary button instance noted around lines
343-345 to keep both toggles accessible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 93ea0ad4-7cb0-4098-8eec-740be80591d6

📥 Commits

Reviewing files that changed from the base of the PR and between f3df55f and 7b243db.

📒 Files selected for processing (1)
  • src/components/layout/Navbar.tsx

@reach2saksham
Copy link
Author

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 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.

@reach2saksham
Copy link
Author

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 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.

@reach2saksham
Copy link
Author

@M4dhav This PR is ready to be merged from my side.

@reach2saksham reach2saksham added enhancement New feature or request new-design labels Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request new-design

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant