1C from right to left: the way we supported RTL in the 1C:Enterprise platform

Peter Gribanov

11.08.2020 14 min

The 1C:Enterprise platform is available in 22 languages, including English, German, French, Chinese, and Vietnamese. Since recently, it is also available in Arabic (version 8.3.17).

One of the distinctive features of the Arabic language is that the text is both written and read from right to left. UI for Arabic has to be displayed horizontally in an inversed manner (but for certain exceptions as there are some twists and turns) and context menu opened to the left of the cursor, etc.

Below you may find more information about the way we supported RTL (right-to-left) in the 1C:Enterprise platform web client and one of the assumptions, which explain why people from the Arab nations write from right to left.


Historical notes

We are all used to write from left to right. This writing direction primarily derives from the fact that when right-handers write text on a paper (statistically, there is about 85 percent of right-handers worldwide), they can see what is already written. Their right (writing) hand does not cover the text. At the same time, the left-handers would take pains.

Below is one of the assumptions "why people in the Arab nations write from right to left." Languages the Arabic derives from were used in times when there was neither paper nor any of its equivalents available (i.e., papyrus, parchment, etc.). The only way to document information was to cut graphic symbols on stones. What is the most convenient technique for a right-hander to handle a hammer and a chisel? Of course, to hold a chisel in the left hand and a stick in the right side and thus tap it on the chisel. And, it is more convenient to write from right to left in this case.

Now, a few words about how we dealt with this lasting legacy. 

How did we approach this problem?

None of the developers spoke Arabic or was previously engaged in projects related to the development of RTL interfaces. We sifted through a lot of articles on RTL. As we reviewed the information available, we came to understand that we needed to engage an Arabic native speaker by all means. Therefore, along with searching for Arabic translators, we started to look for an employee who is an Arabic native speaker with the proper expertise to advise us on distinguishing features of interfaces implemented in Arabic. Having interviewed several applicants, we found a team member we were looking for and got started.

Let's play with fonts

We use Arial, 10pt, throughout our platform by default. A developer of a specific configuration can change fonts for most interface items. However, experience has proven that it is not a common practice. In other words, 1C software users, in most cases, see text labels displayed in various windows in Arial.

Arial is good to display text data in 21 languages (including Chinese and Vietnamese). However, as we managed to find out with the help of our Arab team member, text displayed using this font is tiny and cannot be qualified as readable:

100%:


Generally, all Arab users set higher DPI (125% or 150%). That being the case, things get better. However, text displayed in Arial remains not so easy to read due to the distinctive features of this font.

125%:


150%:


We considered several alternate solutions to this problem.

1.      It is replacing the default Arial font with another font that displays text in all languages supported by the platform (including Arabic) consistently with good quality.

2.      We are increasing the Arial font size to 11 pt in the RTL interface.

3.      It is replacing the default font (Arial) with another font that is more suitable for Arabic and continues using Arial in the LTR interface.

When selecting the most suitable solution, we had to bear in mind that Arial, 10 pt, was used throughout the 1C:Enterprise platform for a long time. Over 1,300 mass-market solutions were developed by our partners and us based on the platform, and Arial, 10 pt, proved to be the right choice for all supported operating systems (Windows, Linux, and macOS of various versions) and web browsers in all cases. The introduction of another font and/or modification of its size would mean that mass testing of the user interface would be required. At the same time, most test procedures could not be automated in this case. Moreover, the use of another font would result in the introduction of a software interface the current users were already used to.

More importantly, we were unable to find a master font that could be used to display text in all languages (including Arabic) with equally good quality. For instance, Segoe UI is suitable to display text in Arabic, even if set at 10pt. However, Chinese is not supported. Moreover, this font is unavailable in several OS. Tahoma is quite good to display text in Arabic, even if set at 10pt. However, there are some problems related to its support in Linux. Further, Roman/Cyrillic letters look too bold, if you select 'bold' (while bold text in Arabic is displayed smoothly). And so forth.

If we used a larger size font (11pt) in RTL interface, this would require an extensive UI testing, since we had to make sure that all the items were displayed correctly and each label was in its place, etc. Even if we use Arial, 11pt, text in Arabic is not displayed correctly.

Therefore, the third solution was found to be the best possible scenario in terms of labor input and expected performance. So, we continue using Arial for all languages, except Arabic. To display text in Arabic, we use Almarai which is the optimal solution for this language. For that purpose, we add the following to CSS:

@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;
}

And, further, whenever a default font is expected to be used, we set the following:

font-family: 'Almarai', Arial, sans-serif;

The benefit of this approach is that if an interface has no characters in unicode-range, the relevant font is not loaded. However, if such characters do exist, your web browser will load the font (or use its local version) and display them using the proper font.

Interface transformation.

As might be expected, the HTML layout of a web client was not ready for 'the transformation'. Having taken the first step and assigned dir="rtl" attribute for the root element with html[dir=rtl] {text-align: right;} style added, we started to do this meticulous work. Throughout this process, we developed many practices (see below) we'd like to disclose.

Symmetry

Let's consider this practice using the buttons as an example. Buttons supported by the platform may contain images, text, and dropdown list markers. The suitable combination is at the discretion of the developers of each application based on the platform.

«Before RTL» column displays initial indents set for button items in graphic form. The indent value is dependent on whether any relevant element is available in the button (or not) and applicable layout. If there is an image, no left indent is required for the text. Or if an image is placed on the right-hand side, it has a negative indent. If there is a dropdown list marker, a larger right indent is required for a text container. If a marker is placed immediately after an image, it has the right indent also. Too many 'if' conditions, except when a button has text only with symmetrical indents. Of course, symmetrical indents! If indents are symmetrical, there is no need to make any transformation. That was the underlying concept.

«After RTL» column displays newly set symmetrical indents applicable to similar buttons. It only remains to deal with an indent between an image and a dropdown list marker. We'd appreciate it if we could find a one-stop solution that can be employed irrespective of applicable orientation. A triangle is drawn with a top border on a pseudo-element so that no indent is required (only if it is placed after an image). That is a precondition for adding a pseudo-element with its width equal to a preselected indent and the triangle and an indent swap around as soon as orientation changes.

Arabic.png

Note. All examples given below are provided for the LTR interface by default. To see examples applicable to RTL interface, enter dir=" rtl" instead of dir=" ltr".

<!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">Settings</span> <span class="buttonDrop"></span> </a> <a class="button"> <span class="buttonImg"></span> <span class="buttonDrop"></span> </a> </body> </html>


We seek to avoid redundant elements, pseudo-elements, and wrappers. However, when we made our choice between a higher number of conditions in CSS and adding a pseudo-element in this case, we opted for the latter due to its versatility. As a rule, a form has a few buttons of this kind. Therefore, performance remains unaffected when adding elements even if you use Internet Explorer.

The principle of symmetry also proved its usefulness when scrolling the bars. To shift content horizontally, margin-left: -Npx; unit property was used previously.

margin-left.png

Now, margin: 0-Npx; symmetric value is set, which applies both to the left and right. The web browser shifts content depending on the direction so specified.

Atomic classes

One of our platform features is that a user can dynamically change content and its location on a form on the go at their discretion. Most typically, users align text horizontally (i.e., left, right, or center alignment). To do that, text-align simple alignment is used with a required value. Adjustment for RTL would mean using extended conditions in scripts and styles per each control and positioning case. The shortest solution would result in four strings:

.taStart {
    text-align: left; 

html[dir=rtl] .taStart {
    text-align: right; 

.taEnd { 
    text-align: right; 
}
html[dir=rtl] .taEnd {
    
text-align: left; 
}

Therefore, a class with the required alignment is set in a relevant location, which can be easily replaced, if necessary. Now, style=" text-align: ..." alignment setting has to be replaced with a proper class.

The similar principle applies when another alignment type is used (float).

.floatStart { 
    float: left; 

html[dir=rtl] .floatStart {
    
float: right; 
}
.floatEnd { 
    float: right; 
}
html[dir=rtl] .floatEnd { 
    float: left; 
}

It also applies for cases when you use a class for mirroring icons, which can be as well placed in any container where mirroring is required in the RTL interface.

html[dir=rtl] .rtlScale {
    transformscaleX(-1); 
}

Antiscale

Now that we have already dealt with 'simple' linear elements, it is time to deal with the 'complex' ones. These elements are also supported by the platform (e.g., switches). Their geometry may vary. The web browser managed to cope with the location of elements, so that indents in our switches were symmetrical by default. So, what is the problem? It's the border-radius.

It is calculated per each switch element depending on its location. 'Top left, 'top-right', 'top right and bottom right' - there is a great number of choices.

You can flip a container with a switch. But what about the text, which will be inverted as well? We call this technique 'antiscale'. An rtlScale atomic class is added to the container for mirroring, while transform: inherit; inheritance property is added to its child element. In the LTR interface, this technique will be ignored, and in RTL interface, text will flip twice and be displayed properly.

row-reverse.png


<!DOCTYPE HTML> 
<html dir="ltr"> 
<head> 
<style> 
html[dir=rtl] .rtlScale { 
   transformscaleX(-1); 

.tumbler {
   display: inline-flex;
   border-radius4px 0 0 4px
   border1px solid #A0A0A0;
   padding4px 8px

.tumblerBox { transform: inherit; 

</style> 
</head>
<body> 
<div class="tumbler rtlScale">
   <div class="tumblerBox">not know</div> 
</div>
</body>
</html>

Flexbox

Unfortunately, we were certainly not the inventors of this fabulous technique. However, we benefited from its functionality with great pleasure to achieve our own goals. The sections panel is a good example. Scroll buttons in this panel require no extra space and are displayed over the panel so that a user can scroll in any direction. Reasonable implementation (position:absolute; right/left: 0;) appeared to be non-versatile and thus we decided not to use it. Finally, a versatile solution took the following form. Zero width is set for a scroll button in a parent container (so that no extra space is required), while the orientation of the scroll button placed at the end is reversed using flex-direction: row-reverse;.


rtlScale.png

Thus, a button at the end of a line is placed against the end of a container line with zero width and is 'mirrored' over the panel.


<!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">Panel content</div> <div class="scroll scrollBack"> <div>Back</div> </div> <div class="scroll scrollNext"> <div>Forward</div> </div> </div> </body> </html>

The idea with zero width turned out to be very useful when solving other tasks. Dropdown items (popup menus, dropdown lists, etc.) are common throughout the platform. Positioning calculations are complex and sensitive. Therefore, mirroring requires extra complexity and sensitivity.

calc.png

The suitable solution is to place a dropdown item in size zero container (the so-called 'anchor'). The anchor is positioned absolutely in a predefined interface location, while its content start edge is placed against the anchor start edge, thus setting the content in the required direction.

<!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">Anchor Content</div> </div> </body> </html>

Objects with absolute positioning

Where absolute positioning of elements is required (style=" position: absolute;" or style=" position: fixed;"), dir=" rtl" is not applicable. As such, a horizontal coordinate shall be applied to right, rather than left.

image

Further, if scrollLeft, offsetLeft element properties are accessed when coordinates are calculated using JS, the direct use of these properties in the RTL interface can result in unexpected consequences. The values of these properties have to be calculated in a different manner. The similar feature implemented in Google Closure Library proved to be really good. We use it in a web client (see https://github.com/google/closure-library/blob/master/closure/goog/style/bidi.js).

Summary

We made it! We transformed and retained the source code in a single version applicable both to the LTR and the RTL interfaces. Although no need arose to date, we could display two different forms with dissimilar directions simultaneously on a single page, if required. Moreover, having employed these approaches, we obtained a final CSS file with a 25% smaller size.

Most importantly, we supported RTL in a thin (native) client running in Windows, Linux, and macOS. However, this should be discussed in a separate article.

Be the first to know tips & tricks on business application development!

A confirmation e-mail has been sent to the e-mail address you provided .

Click the link in the e-mail to confirm and activate the subscription.