Breaking Language Barriers: How We Added Right To Left Compatibility to the Trendyol iOS App

Beyza Sığınmış
Trendyol Tech
Published in
8 min readDec 26, 2023

--

In the ever-evolving landscape of mobile app development, embracing diversity and inclusivity is paramount. As iOS developers, we recently enhanced the Trendyol e-commerce app by introducing Arabic language functionality and ensuring a seamless Right-to-Left (RTL) user interface for six different countries. This article explores the technical details of implementing Arabic language support and RTL functionality.

Research and Preparation

Our journey began with thorough research and careful planning. We studied Apple’s comprehensive RTL documentation and used available resources to establish a solid foundation. With this understanding, we addressed challenges in the application, such as differences in how things were arranged, text alignment issues, and problems with custom UI elements.

Identifying Issues

After a thorough examination of our application in RTL mode, we identified several challenges in various aspects of the user interface and functionality. To effectively communicate these issues, we documented them with example screen captures and detailed explanations.

Recurring issues included problems with the layout of views and cells, which involved manual adjustments. Some views were not automatically flipped, requiring us to recalculate frames for proper RTL alignment. Inconsistencies in text alignment, especially in labels and buttons, were also noted. Custom UI elements didn’t behave as expected in RTL mode, so we had to make specific adjustments to correct their behavior. Icons presented problems that required appropriate mirroring. These findings played a significant role in guiding our RTL adaptation process, ensuring progress towards a polished and seamless user experience.

UAE Application Screens
Differences Between LTR and RTL On Same Pages

Technical Implementation

In achieving the RTL support for our iOS app’s UICollectionView, we provided the necessary support with the following extension.

public final class RTLFlowLayout: UICollectionViewFlowLayout {
public override var flipsHorizontallyInOppositeLayoutDirection: Bool {
isLanguage == .arabic
}
}

extension UICollectionView {
public func addSupportRTLFlowLayout(scrollDirection: UICollectionView.ScrollDirection = .horizontal,
sectionInset: UIEdgeInsets? = nil) {
// Check if the selected language is RTL (Right-to-Left)
guard isLanguage == .arabic else { return }

// Create an instance of the custom RTLFlowLayout class
let flowLayout = RTLFlowLayout()
flowLayout.scrollDirection = scrollDirection

// Update the semantic content attribute based on the selected language
semanticContentAttribute = isLanguage == .arabic ? .forceRightToLeft : .forceLeftToRight

// If a custom sectionInset is specified, assign it to the flowLayout
if let sectionInset = sectionInset {
flowLayout.sectionInset = sectionInset
}

// Set the collectionViewLayout to the custom RTLFlowLayout
collectionViewLayout = flowLayout
}
}

This extension function is designed to be added to a UICollectionView instance in an iOS app. It dynamically adjusts the layout and behavior of cells within the collection view to accommodate RTL language support based on the user’s language selection. The RTLFlowLayout is a custom class responsible for handling the specific layout characteristics associated with RTL languages.

To ensure user-friendly experience in our iOS app, we have implemented a mechanism for adjusting the visual presentation of certain UIKit components based on the semantic content attribute. This is particularly useful when providing support for RTL languages, as the arrangement of elements can differ.

func prepareViewsSemanticContent(semanticContentAttribute: UISemanticContentAttribute) {
// Set the semantic content attribute for various UIKit components
UISwitch.appearance().semanticContentAttribute = semanticContentAttribute
UIView.appearance().semanticContentAttribute = semanticContentAttribute
UILabel.appearance().semanticContentAttribute = semanticContentAttribute
UIPageControl.appearance().semanticContentAttribute = semanticContentAttribute
}

The default implementation inside the protocol extension is designed to streamline this process for common UIKit components. By calling prepareViewsSemanticContent on a conforming type, we can easily set the semantic content attribute for essential elements like switches, views, labels, and page controls.


public extension UISemanticContentAttribute {
static var gulfSemanticContentAttribute: UISemanticContentAttribute {
isLanguage == .arabic ? .forceRightToLeft : .forceLeftToRight
}
}

public extension NSTextAlignment {
static var gulfRegionAlignment: NSTextAlignment {
isLanguage == .arabic ? .right : .left
}
}

public extension TextAlignment {
static var gulfRegionAlignment: TextAlignment {
isLanguage == .arabic ? .trailing : .leading
}
}

public extension HorizontalAlignment {
static var gulfRegionAlignment: HorizontalAlignment {
isLanguage == .arabic ? .trailing : .leading
}
}

These extensions provide streamlined ways to adapt the visual presentation and alignment of UI elements in an iOS app based on the selected language. The UISemanticContentAttribute extension offers a simplified approach to retrieve the semantic content attribute, ensuring consistency in RTL language support. The NSTextAlignment, TextAlignment, and HorizontalAlignment extensions provide quick adjustments for text and horizontal alignment, dynamically switching between right and left alignments in Arabic and other languages. This modular approach enhances the app’s internationalization, offering a more user-friendly experience across various language settings.

scrollView.transform = CGAffineTransformMakeRotation(isLanguage == .arabic ? .pi : .zero)

In the context of a UIScrollView, the code block dynamically adjusts the rotation angle based on the selected language’s writing direction. When the language is set to a RTL script, it applies a rotation of π (pi) radians, facilitating a natural right-to-left scrolling experience.

On the other hand, for LTR languages, no rotation is applied, guaranteeing a smooth left-to-right scrolling behavior.

Image Assets Direction Implementation
enum INTCommonViewsImages: String, ImageSource {
case INTVideoBackIcon

var compatibleWith: UITraitCollection? {
.init(layoutDirection: isLanguage == .arabic ? .rightToLeft : .leftToRight)
}
}

In order to enhance support for RTL languages, the compatibleWith property has been introduced for images in the INTCommonViewsImages enumeration. This property is part of the ImageSource protocol and is designed to accept a UITraitCollection that represents the current environment traits.

The INTCommonViewsImages enum, which serves as a source for image assets, includes the compatibleWith property. This property is configured to retrieve the UITraitCollection associated with the language’s layout direction through the layout directionexpression.

  1. Semantic Content Mode: We stopped setting semantic content mode in the storyboard to avoid visual disruptions caused by language-dependent layouts.
  2. Alignment in Labels: Instead of using specific settings to align text in labels for right-to-left languages, we now dynamically align text programmatically based on the chosen language direction.
  3. Dynamic Image Handling: We moved from static storyboard image configurations to a dynamic, code-based approach. This considers the need for language-specific adjustments with the compatibleWith parameter.
  4. Dynamic Button Configuration: Instead of fixed configurations, we now use code to dynamically adjust content titles and image insets for buttons based on language requirements.
  5. RTL Layout Components: For components supporting RTL layouts, it is recommended to use bidirectional constraints like “leading” or “trailing” for positioning. This ensures proper layout alignment according to the right-to-left direction of the language. It’s advised to avoid setting unidirectional constraints on a component, as shown in the visual example, as the behavior would not be correct.

In our application, even when the language is set to Arabic, we maintain the usage of numeric digits by implementing a mechanism that detects and prevents the input of Arabic characters in certain contexts. We’ve incorporated two functions, isContainArabicChar and isContainArabicDecimalDigits, which check whether a given text contains Arabic characters or Arabic decimal digits, respectively. This helps maintain consistent numeric input across the app.

func isContainArabicChar(text: String) -> Bool {
for character in text {
guard let scalar = character.unicodeScalars.first else {
return false
}
return CharacterSet(charactersIn: "\u{0600}"..."\u{06FF}").contains(scalar)
}
return false
}

func isContainArabicDecimalDigits(text: String) -> Bool {
for character in text {
guard let scalar = character.unicodeScalars.first else {
return false
}

return CharacterSet(charactersIn: "\u{0660}"..."\u{0669}").contains(scalar)
}
return false
}

Moreover, when dealing with date-related functionalities, we enforce the usage of the Gregorian calendar by utilizing a private function named gregorianYears. This guarantees that we handle dates in a consistent way, no matter which calendar system is chosen.

Year Selection Differences While User Using Different Calender
private func gregorianYears(until yearCount: Int) -> [String] {
let calendar = Calendar(identifier: .gregorian)
let currentYear = calendar.component(.year, from: Date())

let years = (currentYear...(currentYear + yearCount)).map { String($0) }

return years
}

Additionally, within the extension for NSNumber, we've configured a NumberFormatter to format values according to the "en_US" locale. This ensures that numeric values are consistently formatted in the Western style, even when the app is set to Arabic, promoting a standardized numeric presentation.

let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US")
Language Selection Screen

Providing an option to change the language within the app is an approach not supported by Apple. Apple recommends users to change their language preferences through the general settings outside of the application. However, due to business requirements, we continue to work daily to improve any issues that may arise from supporting the language change feature.

The relevant resources for addressing these issues are as follows:

Conclusion

Adding RTL support to our app was a big step in our development journey. It was a challenging task, but it made Trendyol’s app more inclusive. We realized that supporting RTL isn’t just a one-time thing; it’s an ongoing effort that needs continuous attention. When we add new features or updates, we always think about making them compatible with RTL to give our diverse user base the best experience. Thanks to our hard work, Trendyol’s e-commerce app can now be used by more people, including those who speak Arabic. We’re committed to making this experience even better. This whole process not only made us better at the technical side but also showed us how important it is to understand different cultures and design things with the user in mind, especially in our globalized world. In summary, going through the RTL support journey taught us a lot and made our app more functional and accessible, proving our dedication to providing top-notch user experiences.

References

https://dev.to/dodoengineering/how-we-translated-the-dodo-pizza-app-into-arabic-2pki

Join Us

Take your career to new heights by becoming a part of our dynamic team at Trendyol. Join us, make a difference as a member of our iOS team, and contribute to our success.

--

--