Skip to content

Control Panel doesn't work correctly with RTL languages #10928

Description

@tao

Bug description

The control panel doesn't work with right-to-left languages.

Screenshot 2024-10-10 at 09 54 30

In the screenshot you can see the site selector has been set to Hebrew and the multi-site selector has also been set to Hebrew in this example.

But as you can see the HTML direction attribute is still set to ltr.

The dashboard layout sets these attributes with a cpDirection() function

<!doctype html>
<html lang="{{ Statamic::cpLocale() }}" dir="{{ Statamic::cpDirection() }}" class="{{ $user->preferredTheme() === 'dark' ? 'dark' : '' }}">
<head>
    @include('statamic::partials.head')
</head>

The cpDirection function calls cpLocale

 // statamic/cms/src/Statamic.php
public static function cpLocale(): string
{
    return config('app.locale');
}

public static function cpDirection()
{
    return TextDirection::of(static::cpLocale());
}

But cpLocale function always returns English because the config is not dynamic

    /*
    |--------------------------------------------------------------------------
    | Application Locale Configuration
    |--------------------------------------------------------------------------
    |
    | The application locale determines the default locale that will be used
    | by the translation service provider. You are free to set this value
    | to any of the locales which will be supported by the application.
    |
    */

    'locale' => 'en',

As the locale is set in the config, it doesn't get updated when the site selector changes to another language.

However the Sites facade has a method to access the selected site:

    public function selected()
    {
        return $this->get(session('statamic.cp.selected-site')) ?? $this->default();
    }

I can't call that in the cpDirection function because it is not a static function, but for testing I'm going to try return the currently selected site:

// statamic/cms/src/Statamic.php
public static function cpLocale(): string
{
   return session('statamic.cp.selected-site') ?? config('app.locale');
}

public static function cpDirection()
{
   return TextDirection::of(static::cpLocale());
}

After making that change the control panel has the correct html attributes:

Screenshot 2024-10-10 at 10 26 01

But the CodeMirror editor is still not using the correct direction, it should look like this:

Screenshot 2024-10-10 at 10 43 20

Here is the config for CodeMirror:

self.codemirror = CodeMirror(this.$refs.codemirror, {
    ...
    direction: document.querySelector('html').getAttribute('dir') ?? 'ltr',
    ...
});

And the direction does seem to be set with a CodeMirror-rtl class but the text direction is not correct:

Screenshot 2024-10-10 at 10 47 00

That is because each line is forced into ltr mode in the stylesheet

Screenshot 2024-10-10 at 10 51 46

If we remove that css then everything works correctly:

Screenshot 2024-10-10 at 10 53 31

Here is the css causing a conflict which comes from the codemirror css

// statamic/cms/resources/css/vendors/codemirror.css
  .CodeMirror-rtl pre { direction: ltr; }

If you take a look at the current CodeMirror css it is as follows:

.CodeMirror-rtl pre { direction: rtl; }

So I do not know why the directions are different in Statamic vs CodeMirror.

If I force the css to rtl in my own css then it seems to work correctly:

// resources/css/cp.css
.CodeMirror-rtl pre {
    direction: rtl !important;
}

Screenshot 2024-10-10 at 11 14 22

In the Statamic CSS it is set to ltr

.CodeMirror-rtl pre { direction: ltr; }

and compared to the CodeMirror CSS

.CodeMirror-rtl pre { direction: rtl; }

Therefore to get the control panel to work correctly it would need to return the current selected site in cpDirection and cpLocale instead of the app locale in config... I am not sure if that will have any side effects.

And the css needs to be fixed, or each user will have to force the text direction in their own css. I am not sure if that will have any side effects for users that use CodeMirror for code editing instead of markdown.

How to reproduce

Shown above

Logs

No response

Environment

Environment
Laravel Version: 10.48.22
PHP Version: 8.2.24
Composer Version: 2.7.7
Environment: local
Debug Mode: ENABLED
URL: localhost:8000
Maintenance Mode: OFF

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: CACHED
Views: CACHED

Drivers
Broadcasting: null
Cache: file
Database: sqlite
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Statamic
Addons: 5
Sites: 27 (English, Arabic, Bulgarian, and 24 more)
Stache Watcher: Disabled
Static Caching: Disabled
Version: 5.30.0 PRO

Statamic Addons
statamic/collaboration: 1.0.0
statamic/eloquent-driver: 4.15.2
statamic/ssg: 3.0.2
stillat/relationships: 2.2.1

Statamic Eloquent Driver
Asset Containers: file
Assets: file
Blueprints: file
Collection Trees: file
Collections: file
Entries: file
Forms: file
Global Sets: file
Global Variables: file
Navigation Trees: file
Navigations: file
Revisions: file
Sites: file
Taxonomies: file
Terms: file
Tokens: file

Installation

Fresh statamic/statamic site via CLI

Additional details

This has been an issue #5942 (comment) that I mentioned two years ago but was not fixed correctly at the time. My translations have kept growing and the issue is having a huge impact on our operations as I have to manually set the text direction in the editor and add the translations myself instead of letting the rest of the team help.

If you believe there may be too many side effects then I have also previously suggested an alternate solution to only flip the text direction of the form fields without effecting the overall LTR direction of the control panel. #5942 (comment)

The ideal solution for us would be to not use the site-selector at all, but rather have the direction of the form fields and markdown field set when choosing a site in the Sites selector, however just getting the RTL text direction to actually work would be amazing.

165978593-91edfe21-6b31-4d1d-a34c-6b4e1b42e9d4

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions