Skip to content

fix(ui): mirror the optimization card layout for RTL languages - #93

Closed
NimaHp wants to merge 1 commit into
itsfatduck:masterfrom
NimaHp:fix/rtl-card-layout
Closed

NimaHp wants to merge 1 commit into
itsfatduck:masterfrom
NimaHp:fix/rtl-card-layout

Conversation

@NimaHp

@NimaHp NimaHp commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Fixes the right-to-left layout of the optimization cards, reported against Persian but affecting every RTL locale (ar-SA, he-IL, fa-IR).

Cause

WPF mirrors text direction and TextAlignment, and nothing else. Measured on this TFM:

Property Mirrored under FlowDirection="RightToLeft"
paragraph direction, TextAlignment yes
HorizontalAlignment="Left" no, stays at x=0
Grid column order no, column 0 stays at x=0
StackPanel / WrapPanel horizontal child order no, first child at x=0
DockPanel.Dock="Left" no

OptimizationPage.xaml hardcoded all of those, so in RTL:

  1. the tag row hugged the left edge instead of the reading start edge,
  2. the tag icon sat left of its label instead of right of it,
  3. the footer kept the badges on the left and the toggle plus the two buttons on the right.

The three-dot details dialog was unaffected, which matches the report: it is single column and text only.

Fix

Two one-way converters in Common/Converters/, bound to Loc.Instance.Direction and registered in UI/Styles/Converters.xaml:

  • ReadingStartAlignmentConverter / ReadingEndAlignmentConverter (FlowDirectionToHorizontalAlignmentConverter, ToEndEdge) pick the reading start or the far edge
  • ReadingStartColumnConverter / ReadingEndColumnConverter (FlowDirectionToColumnConverter, Invert) swap the two footer groups

The tag chip swaps its icon and label through Grid.Column instead of a horizontal StackPanel, and the icon gap became a symmetric Margin because WPF's Grid has no ColumnSpacing. That adds 6px to the chip's leading padding in both directions; the icon-to-label gap is unchanged at 6px.

Verification

Replicated the card footer and the chip with the real converters and measured the arranged coordinates of a 400px card:

footer LeftToRight  badge x=  0  toggle x=320  more x=380
footer RightToLeft  badge x=250  toggle x=  0  more x= 60
chip   LeftToRight  chip x=  0  icon x= 12  text x= 34
chip   RightToLeft  chip x=270  icon x=372  text x=276

LTR is byte-for-byte the old layout, RTL is its mirror.

  • dotnet build optimizerDuck.slnx --configuration Release: 0 warnings, 0 errors
  • full suite with -longRunning 30: Total: 768, Errors: 0, Failed: 0, Skipped: 5
  • csharpier check .: clean (306 files)

Docs

CONTRIBUTING.md gains a "Right-to-Left Languages" section with the mirrored/not-mirrored table and the binding pattern, AGENTS.md gets the one line rule, and the locale count in both (plus the two translated CONTRIBUTING copies' reference in the English file) is corrected from 17 to 18, which went stale when fa-IR merged.

Not in this PR

Only the optimization card template is touched, which is where the report pointed and where the asymmetry is visible. The other pages keep hardcoded edges in their toolbars and detail rows and would need the same treatment; that is a separate pass.

The navigation pane already mirrors itself, which is why the sidebar looked right while the content did not.

WPF mirrors text direction and TextAlignment, but no layout: HorizontalAlignment is absolute, Grid keeps its column order and StackPanel/WrapPanel/DockPanel keep their child order and Dock values. The optimization card template hardcoded all three, so in ar-SA, he-IL and fa-IR the tag row hugged the left edge, the tag icon sat on the wrong side of its label, and the footer kept badges left with the toggle and buttons right.

Adds two one-way converters in Common/Converters and binds them to Loc.Instance.Direction: ReadingStartAlignmentConverter / ReadingEndAlignmentAlignmentConverter for the edge, ReadingStartColumnConverter / ReadingEndColumnConverter for swapping the two footer groups. OptimizationPage.xaml is the worked example.

The tag chip swaps its icon and label through Grid.Column instead of a horizontal StackPanel, and the icon gap became a symmetric Margin because Grid has no ColumnSpacing in WPF.

Verified by replicating the card footer and chip with the real converters and measuring the arranged coordinates: LTR is unchanged (badges x=0, actions x=320 of 400, icon left of the label), RTL mirrors (badges x=250, actions x=0, icon x=372 right of the label).

Also documents the rule in CONTRIBUTING.md and AGENTS.md, and corrects the locale count that went stale when fa-IR merged.
@NimaHp
NimaHp requested a review from itsfatduck as a code owner October 9, 2026 16:49
@NimaHp NimaHp closed this Oct 9, 2026
@NimaHp
NimaHp deleted the fix/rtl-card-layout branch October 9, 2026 17:14
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