Skip to content

Comments

add Arabic (RTL) language support #58

Merged
overtrue merged 10 commits intorustfs:mainfrom
awbx:main
Feb 21, 2026
Merged

add Arabic (RTL) language support #58
overtrue merged 10 commits intorustfs:mainfrom
awbx:main

Conversation

@awbx
Copy link
Contributor

@awbx awbx commented Feb 20, 2026

Pull Request

Description

Adds full right-to-left (RTL) layout support to the console with Arabic (ar-MA) as the
first RTL locale. Switching to العربية mirrors the entire UI — sidebar, spacing, icons,
table headers, and interactive controls — without any manual rtl: overrides scattered
across pages.

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Code refactoring

Changes

Arabic locale

  • i18n/locales/ar-MA.json — full Arabic translations for all UI strings
  • lib/i18n.ts — added ar → ar-MA mapping and exported RTL_LOCALES set
  • components/language-switcher.tsx — registered العربية

RTL direction infrastructure (components/providers/i18n-provider.tsx)

  • Wraps the app in Radix UI's DirectionProvider so every primitive (DropdownMenu,
    Dialog, Select, Popover, Tooltip, etc.) receives direction via React context
  • On every language change, both document.documentElement.dir and the React direction
    state update atomically, keeping the DOM attribute and component context in sync
  • components.json"rtl": true for future shadcn CLI installs

Sidebar (components/app-sidebar.tsx)

  • useDirection() drives side="right" in RTL — sidebar appears at inline-start
  • Scoped CSS selector overrides shadcn's hardcoded text-left with text-start! on all
    menu and sub-menu buttons, without modifying sidebar.tsx
  • Sub-menu indent border: border-lborder-s (logical inline-start)

Logical CSS properties — 15 custom component files

Replaced all physical direction utilities with logical equivalents:

Physical Logical Scope
ml-* / mr-* ms-* / me-* icon-to-text spacing, push-to-end
pl-* / pr-* ps-* / pe-* internal padding
border-r border-e hero panel separator
left-* / right-* (absolute) start-* / end-* overlays, settings button
ml-auto ms-auto flex push to inline-end

Directional arrow icons (RiArrowLeftSLine, RiArrowRightSLine, RiArrowRightLongFill)
received rtl:-scale-x-100 to point the correct way in RTL.

Switch (components/ui/switch.tsx)

  • dir="ltr" on the root pins the internal flex layout so the thumb's translate-x
    animation always travels the correct distance regardless of inherited page direction
  • rtl:scale-x-[-1] (arbitrary-value syntax, guaranteed to compile) mirrors the track
    visually — thumb starts at inline-start (right) when unchecked, slides to inline-end
    (left) when checked

Table (components/ui/table.tsx)

  • text-lefttext-start on TableHead so column headers align to inline-start
  • [&:has([role=checkbox])]:pr-0pe-0 on TableHead and TableCell — in RTL the
    checkbox column flips to the right edge; pe-0 removes the gap toward the adjacent
    column in both directions

InputGroup (components/ui/input-group.tsx)

  • Input padding offsets pr-1.5 / pl-1.5pe-1.5 / ps-1.5
  • Addon outer padding pl-2 / pr-2ps-2 / pe-2
  • Addon negative button/kbd margins ml-[...] / mr-[...]ms-[...] / me-[...]

Testing

  • Manual testing completed

Switch to العربية:

  1. Sidebar appears on the right, collapses to the right
  2. Dropdown menus, dialogs, and selects open in the correct direction
  3. Switch thumb starts on the right (unchecked) and slides left (checked)
  4. Table headers are right-aligned; checkbox column padding is symmetric
  5. InputGroup icon addons sit at the correct edge
  6. Switch back to English → full LTR layout restored without page reload
  7. Hard-reload with Arabic in localStorage → RTL applied immediately after hydration

Checklist

  • Code follows the project's style guidelines
  • Self-review completed
  • TypeScript types are properly defined
  • All commit messages are in English (Conventional Commits)
  • All existing tests pass
  • No new dependencies added

Related Issues

Closes #57

awbx added 10 commits February 20, 2026 22:28
- Add Arabic (ar-MA) locale and RTL_LOCALES set to i18n config
- Register العربية in language switcher
- Wrap app in DirectionProvider driven by i18n language changes
- Set document.documentElement.dir on every language switch
- Flip components.json rtl flag to true for future shadcn installs
- Read direction from DirectionProvider via useDirection()
- Set side="right" when dir is rtl so sidebar appears at inline-start
- Override hardcoded text-left in shadcn variants with text-start!
- Replace physical border-l on sub-menu with logical border-s
Convert all direction-sensitive utility classes to their logical
property counterparts so layouts mirror correctly in RTL without
needing explicit rtl: overrides:

- ml-*/mr-* → ms-*/me-*
- pl-*/pr-* → ps-*/pe-*
- border-r  → border-e
- left-*/right-* (absolute) → start-*/end-*
- ml-auto   → ms-auto

Add rtl:-scale-x-100 to directional arrow icons (prev/next page,
visit-website link) so they flip to point the correct way in RTL.
- text-left → text-start on TableHead so headers align to inline-start
  (right in RTL, left in LTR) instead of always forcing left
- [&:has([role=checkbox])]:pr-0 → pe-0 on TableHead and TableCell:
  in RTL the checkbox column flips to the right edge; removing the
  physical right padding was cutting into the outer gutter instead of
  closing the gap with the adjacent column
Add rtl:-scale-x-100 to the Switch root so the track flips
horizontally in RTL: thumb starts at inline-start (right) when
unchecked and slides to inline-end (left) when checked, matching
native toggle behaviour for RTL locales.
- Input padding offsets pr-1.5/pl-1.5 → pe-1.5/ps-1.5 so the input
  gains breathing room on the correct side when an addon is present
- Addon inline-start padding pl-2 → ps-2, negative margins ml → ms
- Addon inline-end padding pr-2 → pe-2, negative margins mr → me

Ensures icon/button addons sit at the correct edge in RTL without
needing any changes at the call site.
The previous rtl:-scale-x-100 generated no CSS because negative scale
utilities require arbitrary-value syntax. Also, inheriting dir="rtl"
reversed the flex container so the thumb's translate-x values no
longer matched its physical travel distance.

Fix: pin the root to dir="ltr" so the internal thumb animation always
works as designed, then apply rtl:scale-x-[-1] (arbitrary value,
guaranteed to compile) to mirror the entire element visually in RTL —
thumb starts on the right (inline-start) when unchecked and slides
left (inline-end) when checked.
@overtrue overtrue merged commit 8763b6c into rustfs:main Feb 21, 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.

[FEATURE] add Arabic (RTL) language support

2 participants