Repository: wagtail/wagtail

Issue:
Implement icons mirroring of directional icons for RTL languages support
Follow-up to #8051. Part of our push for RTL language support: #7793. We have a lot of icons in the Wagtail admin that are directional (for example an arrow pointing to the right), and would need to be flipped when the admin UI is displayed in a right-to-left language. This is a well-known necessity for RTL support: https://rtlstyling.com/posts/rtl-styling#bidirectional-icons

We need to implement mirroring for all of those icons, most likely in CSS.

---

I believe this could be done for all of our directional icons at once, by adding a `transform: scaleX(-1);` or rotate to all of the icons. My preference would be to do this via a CSS variable at the root if possible – we set the transform once and for all for those directional icons, based on the icon class name (`.icon-angle-double-left`), and simply change the value of the CSS variable for `[dir=rtl]` pages or elements.

Here’s a quick prototype:

```scss
[dir=ltr] {
    --icon-direction: 1;
}

[dir=rtl] {
    --icon-direction: -1;
}

.icon-angle-double-left,
.icon-arrow-right {
    transform: scaleX(var(--icon-direction));
}
```

So the tasks needed would be to:

- [ ] Review all of our icons and determine which ones should get this mirroring treatment
- [ ] Implement the rotation for all icons, either based on what I outlined above, or a similar approach which doesn’t require us rotating icons in each and every instance they are used.
Implement icons mirroring with CSS
Fixes #8127. This implements icons mirroring with the simplest setup, and does a bit of cleanup so said setup is easily previewable in our styleguide. 

## Follow-up

I wanted to implement a better approach but there are compatibility issues between our "SVG symbols sprite" approach to icons and [how directionality is passed through shadow DOM in HTML](https://github.com/whatwg/html/issues/3699). As such, there are two icons left outstanding:

- `tasks`, where the "list bullets" and "list text lines" should be reversed.
- `list-ol`, also where the "list bullets" and "list text lines" should be reversed.

I was hoping we could create those effects with just CSS, but it seems like we’d need separate alternative icons and a way to switch. I’ve left those icons as-is, so I can create a follow-up issue and hopefully we can find a creative solution.

It’d also be nice if people customizing Wagtail could add their own icons, with RTL support, without having to write CSS. Instead find a way to define the icon needs mirroring directly in the markup. But that’s running into the same issues.

## Testing this

To test this, the simplest way is to view the styleguide page in Arabic and make sure all icons are mirrored as appropriate. Here is the [v5.2 styleguide in arabic](https://static-wagtail-v5-2.netlify.app/admin-arabic/styleguide/#icons-section) for reference.

I would also recommend to manually edit the "rtl icons" style declaration in DevTools to add an outline as debug styles. Makes it much simpler to check which icons are reversed.

_Please check the following:_

-   [x] Do the tests still pass?[^1]
-   [x] Does the code comply with the style guide?
-   ~~[ ] For Python changes: Have you added tests to cover the new/fixed behaviour?~~
-   [ ] For front-end changes: Did you test on all of Wagtail’s supported environments?[^2]
    -   [x] **Please list the exact browser and operating system versions you tested**: Safari 17, Chrome 121, Firefox 121 on macOS 14
    -   [x] **Please list which assistive technologies [^3] you tested**: None
-   ~~[ ] For new features: Has the documentation been updated accordingly?~~


Discussion:
Discussed in today’s UI team meeting with @fabienheureux – we’re happy with the `transform: scaleX` approach which he had used on other projects successfully (not sure where the above prototype comes from but I’ve never used this "for real" before).

Fabien is going to review https://codepen.io/thibaudcolas/pen/qBobgWG?editors=1000, a list of all Wagtail’s icons, to check whether they should be mirrored or not for RTL languages. We’ll need to validate this with speakers of RTL languages (Arabic, Hebrew, Farsi).
> Discussed in today’s UI team meeting with @fabienheureux – we’re happy with the `transform: scaleX` approach which he had used on other projects successfully (not sure where the above prototype comes from but I’ve never used this "for real" before).
> 
> Fabien is going to review https://codepen.io/thibaudcolas/pen/qBobgWG?editors=1000, a list of all Wagtail’s icons, to check whether they should be mirrored or not for RTL languages. We’ll need to validate this with speakers of RTL languages (Arabic, Hebrew, Farsi).

I am not a native Arabic speaker, but from my experience with the language (school and family) the only icons that would benefit from mirroring would be lists (bullet points, numbers) so that the bullet is on the right. However, mirroring the numbers does not work as they become unintelligible; in that case a completely different icon would be required.

In Arabic, while the text is right-to-left, numbers are actually left-to-right. So any icons containing sequences of numbers still make sense as-is. Similarly, latin characters should not be mirrored, they are read left-to-right even if intermixed with right-to-left text.
Thank you Vince! I’ve updated the CodePen based on this to set aside all icons that will need a different symbol.
Here’s a more recent record of all the icons we have in use in the CMS: [Available icons](https://docs.wagtail.org/en/stable/advanced_topics/icons.html#available-icons)

As of the latest update from @benenright in https://github.com/wagtail/wagtail/discussions/7793#discussioncomment-7067948, I believe this issue is ready to be worked on. There are still some points of implementation to decide on / figure out as we go:

- Whether icons mirroring is "opt-in" or "opt-out"
- How we support scenarios where an icon needs to be swapped to an alternative in RTL
- How we document which icons are and aren’t to be mirrored
- How we support mirroring for third-party icons


Resolving patch:
diff --git a/wagtail/contrib/styleguide/views.py b/wagtail/contrib/styleguide/views.py
--- a/wagtail/contrib/styleguide/views.py
+++ b/wagtail/contrib/styleguide/views.py
@@ -159,7 +159,6 @@ def get_icons(self):
                     "file_path": icon_path,
                     "name": name,
                     "source": source_match.group(1) if source_match else None,
-                    "icon": icon,
                 }
             )
         return all_icons.items()


Test patch: