Eines der Merkmale der arabischen Sprache ist, dass der darin enthaltene Text von rechts nach links geschrieben und gelesen wird. Die Benutzeroberfläche für die arabische Sprache sollte horizontal gespiegelt sein (aber nicht alles und nicht immer - es gibt Feinheiten), das Kontextmenü links vom Cursor öffnen usw.
Unter dem Strich - darüber, wie wir RTL (von rechts nach links) im Webclient der 1C: Enterprise-Plattform unterstützt haben, und auch eine der Hypothesen, die erklären, warum die arabische Welt von rechts nach links schreibt.

Ein bisschen Geschichte
Wir sind es gewohnt, von links nach rechts zu schreiben. Diese Schreibrichtung wird größtenteils dadurch erzeugt, dass Rechtshänder (und laut Statistik etwa 85% von ihnen) beim Schreiben von Text auf Papier sehen, was bereits geschrieben wurde - die schreibende (rechte) Hand deckt den geschriebenen Text nicht ab. Linkshänder müssen leiden.
Eine der Hypothesen "warum die arabische Sprache von rechts nach links geschrieben wird" klingt so. Die Sprachen, aus denen Arabisch stammt, stammten aus jenen Tagen, als es kein Papier und seine Analoga (Papyrus, Pergament usw.) gab. Es gab nur einen Weg, Informationen aufzuzeichnen - Buchstaben in Stein zu schnitzen. Und wie wird es für Rechtshänder bequemer sein, einen Hammer und einen Meißel zu führen? Natürlich hielt er einen Meißel in der linken Hand und klopfte mit einem Hammer in der rechten darauf. In diesem Fall ist es bequemer, von rechts nach links zu schreiben.
Nun, darüber, wie wir mit diesem Erbe von Jahrhunderten umgegangen sind.
Wie sind wir zur Aufgabe gekommen?
Keiner der Plattformentwickler sprach Arabisch und hatte keine Erfahrung in der Entwicklung von RTL-Schnittstellen. Wir haben viele Artikel zum Thema RTL geschaufelt (ich möchte insbesondere der Firma 2GIS für die geleistete Arbeit und die sorgfältig ausgearbeiteten Artikel danken: Artikel 1 , Artikel 2 ). Als ich das Material studierte, wurde mir klar, dass wir ohne einen Muttersprachler nicht auskommen könnten. Daher suchten wir gleichzeitig mit der Suche nach Übersetzern in die arabische Sprache nach einem Mitarbeiter - ein Muttersprachler der arabischen Sprache, der über die erforderliche Erfahrung verfügt, könnte uns über die arabischen Besonderheiten von Schnittstellen beraten. Nachdem wir mehrere Kandidaten überprüft hatten, fanden wir eine solche Person und machten uns an die Arbeit.
Spielen wir mit Schriftarten
Standardmäßig verwenden wir die Plattformschrift Arial, 10pt. Der Entwickler einer bestimmten Konfiguration kann die Schriftart für die meisten Oberflächenelemente ändern, dies wird jedoch, wie die Praxis zeigt, selten durchgeführt. Jene. In den meisten Fällen sehen Benutzer von 1C-Programmen von Arial geschriebene Inschriften auf ihren Bildschirmen.
Arial zeigt 21 Sprachen gut an (einschließlich Chinesisch und Vietnamesisch). Wie sich jedoch dank unseres arabischen Kollegen herausstellte, ist der in dieser Schriftart gerenderte arabische Text sehr klein und schwer zu lesen:
100%:

Arabische Benutzer arbeiten in der Regel mit einer erhöhten DPI - 125%, 150%. Die Situation in dieser DPI verbessert sich, aber Arial ist aufgrund der Art der Schriftart immer noch schwer zu lesen.
125%:

150%:

Wir haben verschiedene Optionen zur Lösung dieses Problems untersucht:
- Arial , , ( ).
- Arial 11pt RTL-.
- Arial , LTR- Arial.
Bei der Auswahl einer Lösung mussten wir berücksichtigen, dass die Arial 10pt-Schriftart seit sehr langer Zeit in der 1C: Enterprise-Plattform verwendet wird. Auf der Plattform haben wir und unsere Partner mehr als 1300 Edition-Lösungen erstellt, und in allen zeigte sich die Arial 10pt-Schriftart auf allen unterstützten Betriebssystemen (Windows, Linux) und macOS verschiedener Versionen) sowie in Browsern. Das Ändern der Schriftart und / oder ihrer Größe würde massive Tests der Benutzeroberfläche bedeuten, und viele dieser Tests können nicht automatisiert werden. Das Ändern der Schriftart würde auch das Ändern der vertrauten Oberfläche von Programmen für aktuelle Benutzer bedeuten.
Darüber hinaus konnten wir keine universelle Schriftart finden, die alle Sprachen, einschließlich Arabisch, gut repräsentiert. Beispielsweise rendert die Segoe UI-Schriftart Arabisch auch bei 10pt gut, unterstützt jedoch kein Chinesisch und wird auch unter einigen Betriebssystemen nicht unterstützt. Tahoma ist gut darin, arabischen Text mit 10pt zu rendern, hat jedoch Probleme mit der Linux-Unterstützung und "zu fett" lateinisch / kyrillisch für fett (arabisch fett sieht gut aus). Etc.
Das Erhöhen der Standardschriftgröße auf 11pt in der RTL-Oberfläche würde eine Menge UI-Tests bedeuten - wir müssen sicherstellen, dass alles korrekt gerendert wird, alle Beschriftungen in dem dafür vorgesehenen Bereich platziert werden usw. Und selbst bei 11pt zeigt Arial arabische Zeichen nicht perfekt an.
Infolgedessen erwies sich der dritte Weg als optimal in Bezug auf die Arbeitskosten und den erzielten Effekt: Wir verwenden Arial weiterhin für alle Zeichen außer Arabisch. Und für arabische Schriftzeichen verwenden wir dafür eine gut geeignete Schriftart - Almarai . Fügen Sie dazu dem CSS Folgendes hinzu:
@font-face {
font-family: 'Almarai';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Almarai'),
local('Almarai-Regular'),
url(https://fonts.gstatic.com/s/almarai/v2/tsstApxBaigK_hnnQ1iFo0C3.woff2)
format('woff2');
unicode-range:
U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
und wo immer Sie die Standardschrift verwenden müssen, stellen Sie die Schrift folgendermaßen ein:
font-family: 'Almarai', Arial, sans-serif;
Das Schöne an diesem Ansatz ist, dass diese Schriftart nicht einmal geladen wird, wenn sich in der Benutzeroberfläche kein einziges Zeichen befindet, das in den Unicode-Bereich fällt. Sobald ein solches Symbol angezeigt wird, lädt der Browser die Schriftart selbst herunter (oder verwendet die lokale Version) und zeigt das Symbol in der gewünschten Schriftart an.
"Flip" -Schnittstelle
Wie zu erwarten war, war das HTML-Layout des Webclients nicht für einen Flip bereit. Nachdem wir den ersten Schritt unternommen, das Attribut dir = "rtl" für das Stammelement festgelegt und den HTML- Stil [dir = rtl] {text-align: right;} hinzugefügt haben , haben wir mit der sorgfältigen Arbeit begonnen. Im Verlauf dieser Arbeit haben wir eine Reihe von Praktiken entwickelt, die wir hier teilen möchten.
Symmetrie
Schauen wir uns das Beispiel der Schaltflächen an. Schaltflächen in der Plattform können ein Bild, einen Text und eine Dropdown-Listenmarkierung enthalten. Und das alles in jeder Zusammensetzung nach Ermessen der Entwickler von Anwendungslösungen, die auf der Plattform basieren.
Die Spalte "vor RTL" zeigt grafisch die anfängliche Auffüllung der Schaltflächenelemente. Die Abhängigkeit der Anzahl der Einrückungen vom Vorhandensein von Elementen in der Schaltfläche sowie von der Reihenfolge ihrer Anordnung ist offensichtlich. Wenn es ein Bild gibt, benötigt der Text keinen linken Einzug, wenn das Bild rechts ist, dann hat das Bild eine negative Verschiebung, wenn es eine Markierung in der Dropdown-Liste gibt, hat der Container mit dem Text mehr Einzug rechts, wenn der Marker unmittelbar nach dem Bild ist, hat er immer noch einen Einzug rechts. Zu viele Wenns, außer einer Nur-Text-Schaltfläche mit symmetrischer Auffüllung. Symmetrisch! Wenn Sie die Einrückungen symmetrisch verteilen, gibt es nichts zu drehen. Dies wurde die Hauptidee.
In der Spalte "Nach RTL" werden die neuen symmetrischen Einrückungen auf denselben Schaltflächen angezeigt. Es bleibt die Nuance mit dem Einzug zwischen Bild und Listenmarkierung zu lösen. Ich wollte eine universelle Lösung für jede Orientierung. Das Dreieck selbst wird mit dem oberen Rand des Pseudoelements gezeichnet und benötigt nur dann einen Einzug, wenn es hinter dem Bild liegt. Unter dieser Bedingung wird ein weiteres Pseudoelement mit der Breite der erforderlichen Einrückung hinzugefügt. Das Dreieck und die Polsterung tauschen sich selbst aus, wenn die Ausrichtung geändert wird.

Hinweis. Alle folgenden Beispiele gelten standardmäßig für die LTR-Schnittstelle. Um zu sehen, wie das Beispiel in der RTL-Schnittstelle aussieht, ändern Sie dir = "ltr" in dir = "rtl".
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
.button {
display: inline-flex;
align-items: center;
border: 1px solid #A0A0A0;
border-radius: 3px;
height: 26px;
padding: 0 8px;
}
.buttonImg {
background: #A0A0A0;
width: 16px;
height: 16px;
}
.buttonBox {
margin: 0 8px;
}
.buttonDrop {
display: flex;
}
.buttonDrop:after {
content: '';
display: block;
border-width: 3px 3px 0;
border-style: solid;
border-left-color: transparent;
border-right-color: transparent;
}
.buttonImg + .buttonDrop::before {
content: '';
display: block;
width: 8px;
overflow: hidden;
}
</style>
</head>
<body>
<a class="button">
<span class="buttonImg"></span>
<span class="buttonBox"></span>
<span class="buttonDrop"></span>
</a>
<a class="button">
<span class="buttonImg"></span>
<span class="buttonDrop"></span>
</a>
</body>
</html>
Wir versuchen unnötige Elemente, Pseudoelemente und Wrapper zu vermeiden. Wenn Sie in diesem Fall die Wahl zwischen einer Erhöhung der Bedingungen in CSS und dem Hinzufügen eines Pseudoelements treffen, gewinnt die Lösung mit einem Pseudoelement aufgrund ihrer Vielseitigkeit. Das Formular enthält nicht viele solcher Schaltflächen, sodass die Leistung beim Hinzufügen von Elementen auch im Internet Explorer nicht beeinträchtigt wird.
Das Prinzip der Symmetrie hat sich auch beim Scrollen unserer Panels als nützlich erwiesen. Um den Inhalt horizontal zu verschieben, haben wir zuvor einen einzelnen Eigenschaftsrand nach links angewendet: -Npx; ...

Der Wert ist jetzt auf symmetrischen Rand eingestellt: 0 -Npx; d.h. für links und rechts gleichzeitig und wohin bewegt werden - der Browser selbst weiß, abhängig von der angegebenen Richtung.
Atomklassen
Eine der Funktionen unserer Plattform ist die Möglichkeit, Inhalte und deren Position auf dem Formular "on the fly" je nach Geschmack jedes Benutzers dynamisch zu ändern. Ein häufiger Fall von Änderungen ist die horizontale Ausrichtung von Text: links, rechts oder mittig. Dies wird erreicht, indem einfach die Textausrichtung mit dem entsprechenden Wert ausgerichtet wird. Eine Umkehrung für RTL würde bedeuten, dass die Bedingungen in Skripten und Stilen für jedes Steuerelement und für jeden Fall seiner Positionierung erweitert werden. Die minimale Lösung kostet 4 Zeilen:
.taStart {
text-align: left;
}
html[dir=rtl] .taStart {
text-align: right;
}
.taEnd {
text-align: right;
}
html[dir=rtl] .taEnd {
text-align: left;
}
Somit wird die Klasse an den erforderlichen Stellen mit der erforderlichen Ausrichtung installiert und kann bei Bedarf einfach ausgetauscht werden. Es bleibt nur, die Ausrichtungseinstellung durch style = "text-align: ..." durch die entsprechende Klasse zu ersetzen .
Das gleiche Prinzip wird verwendet, um eine andere Art der Ausrichtung festzulegen - float .
.floatStart {
float: left;
}
html[dir=rtl] .floatStart {
float: right;
}
.floatEnd {
float: right;
}
html[dir=rtl] .floatEnd {
float: left;
}
Und wie ohne eine Klasse zum Spiegeln, zum Beispiel Symbole, die auch in allen Containern installiert ist, die in der RTL-Schnittstelle gespiegelt werden müssen.
html[dir=rtl] .rtlScale {
transform: scaleX(-1);
}
Antiskala
Nachdem wir uns mit den "einfachen" linearen Elementen befasst haben, ist es Zeit, zu den "komplexen" überzugehen. Es gibt auch einige auf unserer Plattform, zum Beispiel Kippschalter. Sie können unterschiedliche geometrische Formen haben. Der Browser hat die Anordnung der Elemente bewältigt, die Einrückungen in unseren Kippschaltern sind zunächst symmetrisch. Also, was ist das Problem? Das Problem liegt in der Rundung der Rahmen.
Die Rundung der Rahmen wird für jedes Kippschalterelement in Abhängigkeit von seiner Position berechnet. "Links oben", "rechts oben", "rechts oben und rechts unten" - die Variationen sind unterschiedlich.
Sie können den gesamten Container mit dem Kippschalter umdrehen, aber was ist mit dem Text, der auch umkippt? Wir haben diese Technik "Anti-Scale" genannt . Fügen Sie die Atomklasse rtlScale zu dem Container hinzu, der gespiegelt werden mussund fügen Sie die Transformationsvererbungseigenschaft zu ihrem untergeordneten Element hinzu : inherit; ... In der LTR-Schnittstelle wird diese Methode ignoriert, aber für die RTL-Schnittstelle wird der zweimal gespiegelte Text nach Bedarf angezeigt.

<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
html[dir=rtl] .rtlScale {
transform: scaleX(-1);
}
.tumbler {
display: inline-flex;
border-radius: 4px 0 0 4px;
border: 1px solid #A0A0A0;
padding: 4px 8px;
}
.tumblerBox {
transform: inherit;
}
</style>
</head>
<body>
<div class="tumbler rtlScale">
<div class="tumblerBox"> </div>
</div>
</body>
</html>
Flexbox
Natürlich haben wir uns diese erstaunliche Technologie nicht ausgedacht, aber mit großer Freude haben wir ihre Fähigkeiten für unsere Zwecke genutzt. Zum Beispiel im Abschnittsfenster. Die Bildlaufschaltflächen dieses Bedienfelds belegen keinen Platz. Sie werden oben im Bedienfeld angezeigt, wenn Sie in die eine oder andere Richtung scrollen können. Ganz logische Umsetzung der Position: absolut; rechts / links: 0; Es stellte sich heraus, dass es nicht universell war, also gaben wir es auf. Infolgedessen sah die universelle Lösung folgendermaßen aus: Setzen Sie den übergeordneten Container der Bildlaufschaltfläche auf die Breite Null, damit er keinen Platz beansprucht, und die Ausrichtung der Bildlaufschaltfläche am Ende wurde in Flex-Richtung geändert : Zeilenumkehrung; ...

Somit wird die Schaltfläche am Ende der Zeile gegen das Ende der Zeile des Containers mit der Breite Null gedrückt und über dem Bedienfeld "rückwärts" angezeigt.
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
.panel {
display: inline-flex;
background: #fbed9e;
height: 64px;
width: 250px;
}
.content {
width: 100%;
}
.scroll {
display: flex;
position: relative;
width: 0;
}
.scrollBack {
order: -1;
}
.scrollNext {
flex-direction: row-reverse;
}
.scroll div {
display: flex;
flex: 0 0 auto;
justify-content: center;
align-items: center;
background: rgba(255,255,255,0.5);
width: 75px;
}
</style>
</head>
<body>
<div class="panel">
<div class="content"> </div>
<div class="scroll scrollBack">
<div></div>
</div>
<div class="scroll scrollNext">
<div></div>
</div>
</div>
</body>
</html>
Übrigens erwies sich die Idee der Nullbreite auch zur Lösung anderer Probleme als nützlich. Dropdown-Elemente (Kontextmenüs, Dropdown-Listen usw.) werden auf der Plattform häufig verwendet. Die Positionsberechnung ist komplex und subtil, daher erfordert das Spiegeln noch mehr Komplexität und Subtilität.

Die Lösung besteht darin, das Dropdown-Menü in einen Container mit der Größe Null (Anker genannt) zu legen. Der Anker wird absolut am gewünschten Punkt der Schnittstelle positioniert, und sein Inhalt mit seiner Startkante wird gegen die Startkante des Ankers gedrückt, wodurch der Inhalt in die gewünschte Richtung positioniert wird.
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
.anchor {
border: 1px solid red;
position: absolute;
width: 100px;
height: 50px;
max-width: 0;
max-height: 0;
top: 25%;
left: 50%;
}
.anchorContent {
background: #FFF;
border: 1px solid #A0A0A0;
width: inherit;
height: inherit;
padding: 4px 8px;
}
</style>
</head>
<body>
<div class="anchor">
<div class="anchorContent"> </div>
</div>
</body>
</html>
Absolut positionierte Elemente
Wenn die absolute Positionierung von Elementen nicht vermieden werden kann ( style = ”position: absolute;” oder style = ”position: fixed;” ), ist dir = ”rtl” machtlos. Ein Ansatz kommt zur Rettung, wenn die horizontale Koordinate nicht auf den linken , sondern auf den rechten Stil angewendet wird .

Wenn in JS bei der Berechnung von Koordinaten die Eigenschaften scrollLeft und offsetLeft von Elementen berücksichtigt werden, kann die direkte Verwendung dieser Eigenschaften in der RTL-Schnittstelle zu unerwarteten Konsequenzen führen. Sie müssen den Wert dieser Eigenschaften auf andere Weise berechnen. Die Implementierung dieser Funktionalität in der Google Closure Library, die wir im Webclient verwenden, hat sich bewährt: siehe.https://github.com/google/closure-library/blob/master/closure/goog/style/bidi.js .
Zusammenfassend
Wir haben es geschafft! Wir haben unseren Quellcode in einer einzigen Version für LTR- und RTL-Schnittstellen gespeichert. Der Bedarf ist noch nicht entstanden, aber wenn gewünscht, können wir zwei Formen unterschiedlicher Richtungen gleichzeitig auf einer Seite anzeigen. Übrigens, mit unseren Techniken haben wir die endgültige CSS-Datei 25% leichter gemacht.
Wir haben RTL auch in einem Thin (nativen) 1C- Client unterstützt , der unter Windows, Linux und MacOS funktioniert. Dies ist jedoch ein Thema für einen separaten Artikel.