November 26, 2018

RTL Language Support Lightning

Salesforce classic supports RTL(Right To Left) quite well, but in LEX(Lightning Experience), it's not supported yet. Following screenshot from Salesforce help article clearly indicates the same.

I am sure it should be coming soon, as many are asking for the same on IdeaExchange: https://success.salesforce.com/ideaView?id=0873A000000E2wWQAS

Update: Salesforce came up with Beta for RTL support in Lightning, more details on this article: https://sforce.co/2FJQ2kw 


Why?


Lightning is picking up, and as a consulting company, we can clearly witness the shift. We are getting more App development requests where clients want LEX 1st and classic compatibility, and whole development in Lightning components. Same goes for Community development, it's ONLY around Lightning Components and Lightning Community Builder to develop pages etc. 

We ran into few cases where RTL support in LEX became a critical need, and we have to find a way out. This post suggests a fix or better say HACK, which can get the job done at a decent level. You might need to fine-tune the CSS for individual UI components, as consumed in the various LEX screens. 

How to support RTL?


Mozilla is always a trusted source for any documentation required related to HTML/JS related standards or stuff. Following article explains RTL and its HTML implementation is a quite good detail

Following the same article, the 1st key step to RTL conversion is 

 <html dir="rtl">


adding this simple attribute is a big masterstroke, which does most of the job alone. Though as explained in the Mozilla blog. You need to fix text alignment, padding etc to make sure stuff looks neat in RTL, for ex. following code snippet from the blog, covers both RTL and LTR scenarios: 


html[dir="ltr"] .wrapper .boxContainer .fancyBox {
    text-align: left;
    padding-left: 10px;
}

html[dir="rtl"] .wrapper .boxContainer .fancyBox {
    text-align: right;
    padding-right: 10px;
}


Assuming you read the Mozilla blog, we will move towards a simple lightning code next.


RTL Lightning Component


Lets call this component as lib_lexRTLFix.cmp

HTML Source

<aura:component implements="flexipage:availableForRecordHome,flexipage:availableForAllPageTypes,force:hasRecordId" access="global" >
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
 <!-- This attrib holds the HTML dir = "rtl" and other required markup to make RTL work. -->  
    <aura:attribute name="rtlStyleTag" type="String" default="" />
   
    <!-- This is done for setting right to left when locale is Arabic, Urdu etc-->
    <aura:if 
             isTrue="{!or(equals($Locale.language, 'ar'), equals($Locale.language, 'iw'), equals($Locale.language, 'ur'))}">
        <!-- HTML dir=RTL attribute, and other RTl style fixes will go here -->
        <aura:unescapedHtml value="{!v.rtlStyleTag}" />
    </aura:if> 
</aura:component>


Controller Source lib_lexRTLFixController.js


({
  doInit: function (c, e, h) {
    // add more style elements as you refine the RTL support, keeping it simple for blog post for now
    c.set('v.rtlStyleTag', '<style>html{direction:rtl}</style>'); 
  }
})


Optionally you can add design file to make sure the component name is readable in various page builders etc. 

<design:component label="(LIB) LEX RTL Fix">
 
</design:component>

Most of the code is quite simple and self-explanatory. We have only added HTML RTL direction attribute styling if $Locale.Language is a RTL one. This keeps all the LTR stuff intact, and only injects the hack for RTL as and when needed.

Please Note: This is a basic RTL fix, doing a full-fledged RTL support across all UI elements, would require adding more styles, padding, and alignment stuff. Based on your design requirements, its recommended you tweak your own styles. This is just a good starting point for urgent RTL support for a customer.

How this works?


This component is having no contribution to screen real estate, thus it sits invisibly on any screen and gets the job done. You can safely drag and drop it on lightning home, record, custom and community pages via the standard Salesforce builder. Here is a quick demo of the record page, please notice that page builder reflects the RTL change as soon as the component is dragged drop on the page. There is no visible indication of the component on the page.


Other observations


  1. As LEX works on partial page refresh, once a page is changed and loaded for RTL fix, it keeps on running on rest of the tabs/pages, unless there is a full refresh. 
  2. We worked on implementations and projects involving 100+ lightning components most of the times, to make it easy to reuse this code could go in a lightning base component, which could be extended by all key top-level lightning components. Hereby top level, I mean the components which are dragged on various pages, layouts etc. Inner components don't need it.
  3. A few good developers are trying to fix it the right way, i.e. by fixing SLDS and sending pull requests. But seems to cover various UI components, and its impact is not a simple problem to solve. Here is a pull request for reference and getting more ideas on the same: https://github.com/salesforce-ux/design-system/pull/438