Arabic support and RTL layout fixes#569
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughThis PR adds comprehensive RTL (Right-to-Left) language support by migrating physical left/right Tailwind CSS classes to logical start/end equivalents across 45+ component files, and introduces Arabic language with translations, document direction handling, and language-change event listeners. Changes
Sequence DiagramsequenceDiagram
participant User as User
participant UI as UI Component
participant i18n as i18n Module
participant Document as DOM Document
User->>UI: Click language selector (e.g., Arabic)
UI->>i18n: i18n.changeLanguage('ar')
activate i18n
i18n->>i18n: Load Arabic translations
i18n->>Document: Set lang='ar'
i18n->>Document: Set dir='rtl'
i18n-->>UI: languageChanged event
deactivate i18n
activate Document
Document->>Document: Apply RTL layout
Document-->>UI: Layout reflows with logical CSS properties
deactivate Document
UI->>User: Display Arabic UI with RTL layout
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/i18n/index.ts (1)
20-48:⚠️ Potential issue | 🟠 Major
documentElement.diranddocumentElement.langare never set on initial load.
i18nextdoes not emitlanguageChangedduringinit()for the initially detected language—the event fires only whenchangeLanguage()is explicitly called. SincedocumentElement.diranddocumentElement.langare set exclusively by the listener (lines 44–46), they remain unset on first paint, staying at HTML defaults (typicallyltr/en) even when a persisted language likearis detected. Subsequent user-initiated language switches work fine.Apply the initial direction and language explicitly after
init()completes:🛠️ Suggested fix
+const applyDocumentDirection = (lng: string) => { + document.documentElement.lang = lng; + document.documentElement.dir = i18n.dir(lng); +}; + +i18n.on('languageChanged', applyDocumentDirection); + i18n .use(LanguageDetector) .use(initReactI18next) .init({ // ... - }); - -// Update document direction and lang attribute on language change -i18n.on('languageChanged', (lng) => { - document.documentElement.lang = lng; - document.documentElement.dir = i18n.dir(lng); -}); + }) + .then(() => applyDocumentDirection(i18n.language));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/i18n/index.ts` around lines 20 - 48, The documentElement.lang and .dir are only set in the i18n.on('languageChanged', ...) listener and thus never applied on initial load; after i18n.init completes (use the init callback or the Promise returned by i18n.init) explicitly set document.documentElement.lang = i18n.language (or i18n.resolvedLanguage) and document.documentElement.dir = i18n.dir(i18n.language) so the initial detected/persisted language is applied on first paint; keep the existing languageChanged listener for subsequent changes.
🧹 Nitpick comments (1)
app/src/components/VoicesTab/VoicesTab.tsx (1)
110-110: LGTM — header/search/table padding swaps look correct.
start-*/end-*/ps-*properly flip withdir. The arbitrary-variant rule[&_td:first-child]:ps-8is also correct:td:first-childis DOM-order, and in RTL the column visually appears on the right whereps-8resolves to right padding — the start-of-row gutter is preserved in both directions.Minor nit (optional):
ps-8 pe-8on Line 113 could be justpx-8since both sides are equal —px-*is dir-agnostic and shorter.Also applies to: 113-113, 118-118, 123-123, 127-127, 141-141
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/components/VoicesTab/VoicesTab.tsx` at line 110, Replace paired direction-specific padding classes that are symmetric with the dir-agnostic shorthand: locate the elements in VoicesTab (e.g., the div with className "absolute top-0 start-0 end-0 h-16 bg-gradient-to-b from-background to-transparent z-10 pointer-events-none" and the other elements around the same block using "ps-8 pe-8") and change any "ps-8 pe-8" occurrences to "px-8" (also apply the same substitution for the other listed occurrences at the nearby elements referenced in the comment).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/components/CapturesTab/CaptureInlinePlayer.tsx`:
- Line 147: The Play icon uses a logical margin class "ms-0.5" which flips in
RTL and pushes the right-pointing glyph further off-center; update the class on
the Play element in CaptureInlinePlayer (and any other Play/Pause glyph usages)
to a physical left margin such as "ml-0.5" (or equivalent non-logical class) so
the small leftward optical nudge remains correct in both LTR and RTL.
In `@app/src/components/CapturesTab/CapturesTab.tsx`:
- Line 101: The badge uses logical positioning (-end-1) which flips in RTL;
update the span class in the CapturesTab component so the side-hint stays
physically on the right by replacing "-end-1" with "-right-1" wherever the
side-hint badge is rendered (the span that pairs with modifierSideHint()). Apply
the same change to the matching badge occurrences in the ServerTab CapturesPage
component and the ChordPicker component so all physical-right modifier badges
use "-right-1" instead of "-end-1".
In `@app/src/components/ChordPicker/ChordPicker.tsx`:
- Around line 202-206: The badge anchoring uses logical "-end-1" which flips in
RTL but modifierSideHint(name) expresses a physical side; to preserve
physical-side semantics change the span's class from "-end-1" to "-right-1"
(locate the span rendering the side badge in ChordPicker.tsx that shows {side})
so the "L"/"R" indicator remains on the visual right regardless of text
direction.
In `@app/src/components/Generation/FloatingGenerateBox.tsx`:
- Around line 261-262: Replace the mixed physical positioning classes in
FloatingGenerateBox (the conditional class string that currently uses
"left-[calc(5rem+360px+1.5rem)] right-8" and the non-stories branch
"left-[calc(5rem+2rem)] right-8 lg:end-auto
lg:w-[calc((100%-5rem-4rem)/2-1rem)]") with logical counterparts so RTL flips
correctly: convert the physical left/right to start/end (e.g.,
"start-[calc(...)] end-8") and change the lg override from "lg:end-auto" to the
corresponding logical lg:start-auto if needed, ensuring both the stories and
non-stories branches use start/... and end/... consistently while preserving the
lg width override on the non-stories branch (refer to the conditional class
construction in FloatingGenerateBox.tsx).
- Line 384: Tooltip centering breaks in RTL because the span uses logical
"start-1/2" with physical "-translate-x-1/2"; update the tooltip anchor classes
in FloatingGenerateBox.tsx (the tooltip span elements used for
Generate/Persona/Instruct tooltips) so centering is direction-safe: either
revert to physical anchoring by using "left-1/2 -translate-x-1/2" instead of
"start-1/2 -translate-x-1/2", or keep "start-1/2" and add an RTL-aware
translation like "start-1/2 -translate-x-1/2 rtl:translate-x-1/2"; apply the
same change to all four tooltip span occurrences in this component.
In `@app/src/components/StoriesTab/StoryTrackEditor.tsx`:
- Line 1283: The timeline was flipped to logical direction but the timeline math
and inline left coordinates remain physical; fix by pinning the timeline root to
LTR and restoring physical directional classes: add dir="ltr" to the
StoryTrackEditor root element (component StoryTrackEditor) and revert any
logical Tailwind classes in this file back to their physical equivalents
(replace start-0/end-0 -> left-0/right-0, border-e -> border-r, rounded-s-* ->
rounded-l-*, rounded-e-* -> rounded-r-*) on the corner spacer, track rows,
track-label column, clips sub-container, trim handles, scroll-zoom handles, and
any other elements mentioned so existing inline style left: math and pointer
calculations (the clientX/rect.left/scrollLeft/- LABEL_COL_WIDTH code, playhead
auto-scroll, and styles applied on clips, markers, playhead, and clips
sub-container) continue to work without rewriting coordinate logic.
In `@app/src/components/ui/alert-dialog.tsx`:
- Line 36: Replace the invalid tailwind animate direction tokens "start" with
"left" in the slide classes so the tailwindcss-animate utilities generate CSS:
change data-[state=closed]:slide-out-to-start-1/2 ->
data-[state=closed]:slide-out-to-left-1/2 and
data-[state=open]:slide-in-from-start-1/2 ->
data-[state=open]:slide-in-from-left-1/2 in the AlertDialog content class (the
string containing those data-[state=...] slide-* tokens) and make the identical
replacement in the Dialog component where the same tokens appear.
In `@app/src/components/ui/dialog.tsx`:
- Line 38: The dialog's class string in app/src/components/ui/dialog.tsx uses
logical-direction animation utilities `slide-out-to-start-1/2` and
`slide-in-from-start-1/2` which are provided by tw-animate-css, not the
installed tailwindcss-animate; update the class list in the Dialog component to
use physical-direction equivalents supported by tailwindcss-animate (e.g.,
replace those logical utilities with `slide-out-to-left` / `slide-in-from-left`
for LTR or `slide-out-to-right` / `slide-in-from-right` for RTL), or remove the
slide-related classes entirely if you prefer only fade/zoom animations—ensure
you edit the string where the Dialog element's tailwind classes are defined so
the runtime animations match the installed plugin.
In `@app/src/components/ui/dropdown-menu.tsx`:
- Line 41: The data-[side] animation classes in dropdown-menu.tsx are using
logical "slide-in-from-start/end" which flips in RTL; update the inline-axis
mappings so physical sides map to physical slide directions: replace
data-[side=left]:slide-in-from-end-2 with data-[side=left]:slide-in-from-right-2
and replace data-[side=right]:slide-in-from-start-2 with
data-[side=right]:slide-in-from-left-2 in the class string used by the
DropdownMenu content (and apply the same change in popover.tsx and select.tsx
where the identical data-[side] mappings appear) so left always slides in from
the physical right and right always slides in from the physical left.
In `@app/src/components/ui/popover.tsx`:
- Line 19: The animation classes use non-existent logical utilities
(`slide-in-from-start/end`, `slide-out-to-start`) from tailwindcss-animate
v1.0.7; update all occurrences to their physical equivalents so animations work:
replace "start" with "left" and "end" with "right" while preserving suffixes
(e.g., `slide-in-from-start-2` -> `slide-in-from-left-2`, `slide-out-to-start-1`
-> `slide-out-to-left-1`) in the popover class string in the Popover component,
the dropdown-menu class strings in DropdownMenu, the select animations in
Select, and the dialog/alert-dialog animation classes in Dialog and AlertDialog.
In `@app/src/components/ui/select.tsx`:
- Line 68: Replace the non-existent Tailwind utilities slide-in-from-end-2 and
slide-in-from-start-2 with the physical-direction utilities
slide-in-from-right-2 and slide-in-from-left-2 (respectively) in the
SelectContent class string inside Select (file:
app/src/components/ui/select.tsx) so the animation is generated; likewise update
the same replacements in the corresponding class strings in dropdown-menu.tsx,
popover.tsx, dialog.tsx and alert-dialog.tsx, keeping the data-[side=*] usage
as-is because Radix already provides the physical side after RTL flipping.
In `@app/src/components/ui/slider.tsx`:
- Line 17: Update the Tailwind utility in the SliderPrimitive.Thumb class to use
the v4-compatible logical inset name: replace the token "after:start-1/2" with
"after:inset-s-1/2" inside the className string on the SliderPrimitive.Thumb
component so positioning works correctly and supports RTL in Tailwind v4.
In `@app/src/components/VoiceProfiles/SampleList.tsx`:
- Line 109: The Play icon uses the RTL-sensitive utility ms-0.5 which flips the
optical-centering nudge in RTL and offsets the right-pointing Lucide Play glyph
the wrong way; change the className on the Play component (and verify Pause if
it uses a nudge) to use ml-0.5 (left margin) instead of ms-0.5 so the 2px visual
compensation stays correct regardless of document direction — update the JSX
where Play is rendered (refer to the Play component usage and its className) to
replace ms-0.5 with ml-0.5.
In `@app/src/i18n/locales/ar/translation.json`:
- Around line 95-96: Several Arabic plural keys currently only define _one and
_other (e.g., shortcutNotArmedDescription_one/other, itemCount_*, effectCount_*,
generatingCount_*, lineCount_*, clearFailedDialog.body_*); add the missing
Arabic CLDR plural forms _zero, _two, _few, and _many for each of these key
groups so i18next can select the correct form for 0, 2, 3–10, and 11–99; keep
existing placeholders (e.g., {{names}}) unchanged and provide grammatically
correct Arabic strings for each new key variant to match the existing _one and
_other meanings.
---
Outside diff comments:
In `@app/src/i18n/index.ts`:
- Around line 20-48: The documentElement.lang and .dir are only set in the
i18n.on('languageChanged', ...) listener and thus never applied on initial load;
after i18n.init completes (use the init callback or the Promise returned by
i18n.init) explicitly set document.documentElement.lang = i18n.language (or
i18n.resolvedLanguage) and document.documentElement.dir =
i18n.dir(i18n.language) so the initial detected/persisted language is applied on
first paint; keep the existing languageChanged listener for subsequent changes.
---
Nitpick comments:
In `@app/src/components/VoicesTab/VoicesTab.tsx`:
- Line 110: Replace paired direction-specific padding classes that are symmetric
with the dir-agnostic shorthand: locate the elements in VoicesTab (e.g., the div
with className "absolute top-0 start-0 end-0 h-16 bg-gradient-to-b
from-background to-transparent z-10 pointer-events-none" and the other elements
around the same block using "ps-8 pe-8") and change any "ps-8 pe-8" occurrences
to "px-8" (also apply the same substitution for the other listed occurrences at
the nearby elements referenced in the comment).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 88fdade0-4bda-4d13-aed9-7964e9f36f65
📒 Files selected for processing (50)
app/src/components/AudioPlayer/AudioPlayer.tsxapp/src/components/AudioTab/AudioTab.tsxapp/src/components/CapturePill/CapturePill.tsxapp/src/components/CapturesTab/CaptureInlinePlayer.tsxapp/src/components/CapturesTab/CapturesTab.tsxapp/src/components/ChordPicker/ChordPicker.tsxapp/src/components/Effects/EffectsChainEditor.tsxapp/src/components/Effects/GenerationPicker.tsxapp/src/components/EffectsTab/EffectsDetail.tsxapp/src/components/EffectsTab/EffectsList.tsxapp/src/components/EffectsTab/EffectsTab.tsxapp/src/components/Generation/FloatingGenerateBox.tsxapp/src/components/Generation/ParalinguisticInput.tsxapp/src/components/History/HistoryTable.tsxapp/src/components/ListPane.tsxapp/src/components/MainEditor/MainEditor.tsxapp/src/components/ServerSettings/GpuAcceleration.tsxapp/src/components/ServerSettings/ModelManagement.tsxapp/src/components/ServerSettings/UpdateStatus.tsxapp/src/components/ServerTab/CapturesPage.tsxapp/src/components/ServerTab/ChangelogPage.tsxapp/src/components/ServerTab/GeneralPage.tsxapp/src/components/ServerTab/GenerationPage.tsxapp/src/components/ServerTab/GpuPage.tsxapp/src/components/ServerTab/MCPPage.tsxapp/src/components/Sidebar.tsxapp/src/components/StoriesTab/StoriesTab.tsxapp/src/components/StoriesTab/StoryChatItem.tsxapp/src/components/StoriesTab/StoryContent.tsxapp/src/components/StoriesTab/StoryList.tsxapp/src/components/StoriesTab/StoryTrackEditor.tsxapp/src/components/TitleBarDragRegion.tsxapp/src/components/VoiceProfiles/ProfileForm.tsxapp/src/components/VoiceProfiles/ProfileList.tsxapp/src/components/VoiceProfiles/SampleList.tsxapp/src/components/VoicesTab/VoiceInspector.tsxapp/src/components/VoicesTab/VoicesTab.tsxapp/src/components/ui/alert-dialog.tsxapp/src/components/ui/dialog.tsxapp/src/components/ui/dropdown-menu.tsxapp/src/components/ui/multi-select.tsxapp/src/components/ui/popover.tsxapp/src/components/ui/select.tsxapp/src/components/ui/slider.tsxapp/src/components/ui/table.tsxapp/src/components/ui/toast.tsxapp/src/hooks/useAutoUpdater.tsxapp/src/i18n/index.tsapp/src/i18n/locales/ar/translation.jsonapp/src/router.tsx
|
@coderabbitai help |
|
Only users with a collaborator, contributor, member, or owner role can interact with CodeRabbit. |
Hey, I've added Arabic language support to the app. This includes the full translation file and a bunch of UI fixes to support RTL layouts properly.
I switched most of the Tailwind classes from physical properties (left/right) to logical ones (start/end) so the layout flips automatically when the language is changed. I also added a small listener to i18next to update the document direction.
Everything should look the same as before for English and other LTR languages.
Summary by CodeRabbit
New Features
Style