Saturday, March 04, 2017

Localization Experience in Swift Project

When I tried to jump into localization for my app, I thought it would be a simple job. Actually, I have encountered several hurdles during this progress. Here I would like to make some notes about issues I had experienced.

Bomb! Unexpected Exception

I started to add supporting to two sets of Chinese(my native language): mainly string files such as .strings, and .stringsdict files. This can be done by clicking on Localization button on the right Utilities panel in Xcode. By enabling localization, Xcode would move the English string or plist file from project root into en.lproj folder, and creating other language folders for localized resources, for example, zh-Hant.lproj for Simplified Chinese.

One thing I noticed is that plist file also has Localization section in Xcode right Utilities panel. I thought this could be localized and I did see some settings in some plist file requiring localization. Then I tried to localize plist file together. That's a mistake. See the following sections.

I have a long list of resource files. I spent about 2 days to finish localization for my project. With all the resource files ready, I stared to compile my project and tried to start my test on Simulator. Bomb! I saw this exception right away.

That's really bizarre exception. What does it mean by "Invalid argument"? It does not provide any detail clue about the exception. I had to try internet search to find out if any other people experienced the same issue.

No Solutions Anywhere

Soon I found out this is a common issue for some Swift developers and some suggestions were provided. Unfortunately, I tried all the solutions provided, but I could not resolve this exception in my case. Two days passed, I was really in struggle stage and with no clue to fix the issue.

With no way to get out, I stood back for a moment. With so many changes in my codes, I might mess up somewhere in my project. Instead of finding a way out of the maze, what I could do is to move my project back to the previous working version and redo the localization again. This was the last and difficult choice because I did not want to give up my localization effort.

Roll Back to Previous Working Version

I decided to discard all the changes in my codes from Source Control (fortunately, I have kept doing source code repository by using Xcode Source Control feature) and rolled back to previous version. This time, I started to do one change, and then compiling my project and running my app on Simulator at a time. In this way, I could figure out where the exception would be. I was also very careful coding localization to avoid any error causing unnecessary changes in my project.

I started from my app's settings, i.e, my app name, location privacy description, and app settings, where some localizations are required. I was so lucky that I soon located the issue which caused the exception.

Don't Localize info.plist

[app_name]-info.plist is a project property file, where project settings specific to my app are defined. For simplification, I call this info property file as info.plist in this blog. I need to localize my app display name and location privacy description in this plist.

In Xcode, all string files and plist files can be localized by clicking on Localize... button in Localization section on right Utilities penal.

When a resource file is localized, the English version file is moved from project root to en.lproj folder, and other localized files are created under corresponding language folders, for example, zh-Hans.lproj is the folder for Simplified Chinese resource files.

The problem is that info.plist file would be missing from project root if it were localized. The compile and installation processes require info.plist at project root. Actually, there is a resource file infoPlist.strings for info.plist localization purpose!

To verify this, I discard my changes again. For my working version, I found Identify section in my project settings (select my app as target, in General tab):

However, the same setting would be like as follows if the info.plist is localized.

Even I tried to locate the info.plist file from Choose button, I could not locate it from the dialog window.

Don't Localize Plist?

While I am writing this blog, I realize that none of plist files in my project require localization directly. Further exploration of the APIs Apple provides for localization, all strings files are automatically localized without any reference to device local settings from API interface calls. However, to load a plist, it seems that you have to specify a path for the plist file.

I remember that when I initially added a localization language to my project, from Info tab in project settings:

I saw a prompt dialog for adding new language for only two items: infoPlist.strings, which is for info.plist, and MainStoryboard.storyboard.

For info.plist file, Xcode provides corresponding infoPlist.strings file for localization. In my project, another place where a plist file is used is for my app default settings.

Localization of App Default Settings

The app default settings are defined in a bundle file: Settings.bundle, where a plist file Root.plist, which for default settings, and an English localization strings file within en.lproj folder, are created by Xcode at the time when the project was initially created.

To localize default settings for another language, a language folder and strings file have to be created manually(as in above zh-Hans.lproj and zh-Hant.lproj). The reason is that the plist file and strings files are within the bundle file and there is no Localization section in the right Utilities panel for adding new languages.

I found out that in order for settings working for any other languages, do not remove one item in Root.plist file: Strings Filename and its value as Root.

I had trouble to make default settings working while I was making changes in Root.plist file. I did not understand the usage of that item and removed it from the plist when I tried to clean up default settings. I was tumbled by this mistake. Anyway, it is a good experience and I now fully understand its importance.