Since iOS 6 it has been the case that any localization that utilises a right-to-left language (such as Arabic) will automatically flip your views so that everything scans from right-to-left. Usually this is desireable but there are certain instances where you may want to disable this functionality (such as with a media player that should scrub from left-to-right). I was recently asked by a client to completely disable the right-to-left functionality for all languages as it was causing too many display issues within the app and customers were specifically saying they’d prefer it to scan that way.
After a bit of searching, the general consensus was that I’d need to manually alter1 all of my horizontal constraints in order to force them to be left to right rather than leading to trailing which will flip based on localization. In a project with 1000s of these constraints this did not seem a suitable course of action and would require any future developers on the project to keep this in mind when creating new constraints.
Instead, I came across a property added to UIView in iOS 9 named
semanticContentAttribute. This allows you to choose
unspecified (the default which flips based on localization),
spatial which are special cases for media controls or directional controls, and
forceRightToLeft which work as their names would suggest. Thanks to the
UIAppearance protocol, disabling the flipping globally is a simple one-liner:
UIView.appearance().semanticContentAttribute = .forceLeftToRight
This not only flips all content back to left-to-right but also ensures that your
UINavigationController will animate from left-to-right as well. Of course, you can also use the
appearanceWhenContainedIn: method to limit this global change to specific view controllers of your app should you wish to or to set certain controls to other directions.
The only other thing I needed to change in my project to get this all working was some paragraph styles for attributed strings. I frequently use
NSMutableParagraphStyle to set custom line heights and I leave the other properties to their defaults. One of these is
alignment which is always left on my devices due to my English language but the default is actually
natural which means it renders depending on the language. Searching through my project and finding the few places I’d left out a default and setting it was fairly trivial:
let paragraph = NSMutableParagraphStyle() paragraph.lineSpacing = 4.0 paragraph.alignment = .left
In total, I only needed to make 8 edits to my project; much easier than trying to edit every horizontal constraint in your storyboard!
If I had gone down that route I likely would have written a build script that would go through every xib and storyboard file and do this for me but I have been burned by manually editing xib files in the past. That’s a young man’s game! ↩︎