At the end of last week, I updated two of my existing apps on the App Store to support changing languages within the apps themselves. While I already have this functionality in two of my other apps, the apps I just added this to has a much solid use case, and is arguably something I should have done a long time ago.
In most cases, this won’t be a part of an app’s core functionality; it will merely be an added convenience for a few users at best. This is most certainly true for my two utility apps, Sthlm Travel and Cryptoverter. But there are a few scenarios where this functionality could come in handy.
Accessing localized content
For my other two apps however, I’ve Never and The Blame Game, this could give a substantial boost to user experience. These two apps, which are meant to be used as ice breakers at parties, contains a large amount of localized content for both English and Swedish.
Many Swedish people I know prefer to have their phone language set to English, which means that they will only have access to the app’s content in English. But in company with Swedish friends, they will most likely want to use the Swedish content. So rather than having to change the system language, having a switch in the app is a much more convenient solution.
Another good use case is to make it easier for your testers. Through Xcode, it’s possible for us developers to deploy our apps in the localization of our choice. We can also deploy the app to the simulator, where we can easily set up multiple simulators - each with its respective localization set. But for the testers, you want a simple and straightforward way for them to switch between languages. They shouldn’t have to deploy their app through Xcode, or change their system language each time.
As you may already know, the app per default will choose a localization based on your language settings, either by looking at your system language or the following languages you have prioritized. If none can be found, the default language set by the developer will be used.
Apple doesn’t recommend tampering with this functionality. Instead, they want you to access localized content by using
Since each supported language gets its own language-specific folder with the
.lproj extension in a project, (i.e
en.lproj for English) accessing language specific content is quite simple:
To easily handle the switching between languages, I created a utility class:
Setting preferred language
To set the preferred language, one only needs to change the
preferredLocalization variable of the class.
And to add more supported languages, one can simply extend the
PreferredLocalization enum, with the raw string value as the language designator (more info can be found here).
Getting localized content
I went ahead and created a global function, to replace
LocalizedString. This function simply calls the
localizedString function of
LanguageHandler, which in turn will check the preferred language set, and either use
NSLocalizedString or call its current bundle’s
As for fetching other localized content, simply use
LanguageHandler.default.currentBundle instead of
Being notified on language changes
You may have noticed that this file contains a defined
PreferredLanguageDidChange. This notification gets posted when the preferred localization has changed. Listening to such notification could look like this:
In a larger project however, this could get a bit annoying; having to identify all the places where views needs to dynamically update to language changes. To solve this, I chose to extend some work originating from a friend of mine. He originally created subclasses of
UIButton, and other classes that displays strings, to be able to avoid scenarios where you have to create an
IBOutlet just to set a localized string. Since I found his approach to be quite useful, I chose to further extend his work - by adding handling of language changes:
By using this
LocalizableLabel you only need to set the
textIdentifier, either in a Storyboard/Xib or programatically. The rest is taken care of by the label.
I’ve put up a sample project on my Github to demonstrate everything in action. As always, I’m open to feedback and suggestions!