Clean iOS Localizable Files

Gino Wu
Building VTS
Published in
6 min readApr 3, 2018

--

Updated: For an optimized, easier-to-read, and Swift-ier solution — I rewrote the script from bash to swift to help you keep your localizable files clean and maintainable! Enjoy!
https://medium.com/stash-engineering/how-to-keep-your-ios-localizable-files-clean-swift-script-edition-a01bc649ef1d

Apple makes it simple for their developers to create an app localized to the devices language, however, keeping those localizable files concise and clean is a different story especially as your app matures and supports multiple languages. (Here is a tutorial on how to localize your app: https://medium.com/lean-localization/ios-localization-tutorial-938231f9f881)

What often happens with the Localizable.strings files is that they have a tendency to become large and sloppy fairly quickly. As many engineers can attest, adding code is often easier than modifying or editing existing code, and adding new key/value pairs to the localizable files is no different. It is much easier to add pairs than it is to search for an existing pair to reuse. Ignoring the opportunity to reuse an existing pair can cause a ton of duplication in your localizable files, resulting in unexpected view behaviors. If there’s one thing Clean Code has taught us, it’s to not violate the DRY principle!

Needless to say, the structure of the localizable files is important. A well-sorted localizable file is not only aesthetically pleasing, it also aids with searching and glancing at the file for existing pairs. However, maintaining a well-sorted file is not work effective, which enables developers to add new pairs arbitrary to the files.

Another common problem we see in localizable files are the actual usage of the keys. Frequently, as developers continue to bloat these files, engineers forget to delete unused key/value pairs when code is removed (including me 😅), especially when whole files are deleted. We also see the reverse, in which localizable keys are being used in code, but the developer forgets to define the pair in the localizable files. The latter is much worse since users may see an unreadable string being displayed on a view. Nevertheless, both cases are extremely easy to achieve since the project will continue to build on Xcode without ever throwing any errors or warnings.

Here are examples of the problems described above:

  1. Key duplications:

2. Keys between multiple localizable files do not match:

3. Unused keys:

4. Undefined keys:

To mitigate these problems, we can create an automated post build script that cleans, maintains, and throws warnings or errors on Xcode for any usage problems. The first thing our script should do is find all our localizable files in our project, sort the keys, and identify any key duplications. Easy enough:

First, we define our project name, in this example we’ve named it CleanLocalizableExample and an exit status if a duplicated key is found. We then define a method that takes in a file, removes any white spaces within the file and sorts each line. With a bit of sed and regex, we can extract the localizable keys from file by retrieving the string between the first set of quotes (i.e "Fruit:Apple = "苹果 -> "Fruit:Apple" ) After extracting the keys, we verify the keys for duplicates. If any duplicated keys are found, the script will output the keys and throw an error. The neat thing about Xcode, is if the script executes echo "error:" or echo "warning:" — the IDE will display the corresponding alerts just like any other build errors or warnings during a typical compile process making them extremely hard to miss. The last part of this script locates all files with the name Localizable.strings from the root of your project and executes sort_and_find_duplicates on it. Next we’ll add a function that verifies if the keys from the base localizable file matches all the keys in each of the other localizable files in the project. This will make sure the engineer does not forget to add or delete a key/value pair in one of the localizable files when modifying them.

In the keys_match method, we store all the keys from the base localizable file to a variable named base_keys then store all the keys from the localizable file named localizable_key. We use sed to extract the keys just as the previous method and diff to check for key differences. If the keys between any of the localizable files do not match, Xcode will throw a build error and output the keys that are missing from each file. At this time, the files should be sorted, with no duplicated keys, and all the localizable files contain the same keys project wide. The files should be aesthetically clean and easier to read at this point. The next two methods will verify the actual usage of the keys.

The keys_not_used method loops over the development base keys and applies a grep for NSLocalizedString("$key" over the entire project in .m and .swift files. If the key is not being used in a swift or objective c file, the script throws a Xcode warning. This method may need minor tweaks to suit your project correctly if a convenience init is being used for NSLocalizedString in which you may want to grep a different pattern. If the project includes localized string testing in the testing suite, exclude the testing suite path in the grep function. The result of the method will output the keys not being used and throws a warning rather than an error since having a defined pair without its usage is harmless from a user standpoint. This can be easily modified to an error if you decide to be more strict.

The last method keys_not_included checks for the usage of keys in code that has not been defined in the base localizable file — in which IS harmful from a user standpoint. Similar to the keys_not_used method, this method uses grep for the pattern NSLocalizedString("*" in .swift and .m files, removes any outputs with %d (for localized plural patterns), sorts and uniques the keys and then compares the output to the base localizable file. Ideally, the output keys should match the base localizable file, if not, this method will throw an error and output the keys that are missing in the localizable file. Now let’s put it all together!

Save the file to a folder named scripts in your root directory and add it to your post build script in Xcode.

Build your project and you should now see any errors or warnings caused by your localizable files, click on the report navigator for details on which keys or files caused the issue.

The advantage of adding this script to the post build is that you’ll never have to think about maintaining your files again and the script will be baked into your builds — throwing warnings and errors when necessary. There’s always room for improvement in the script, but for now, this does the trick! I’ve included a sample of the project below on Github.

Please leave any comments, improvements, or suggestions below! Happy Coding!

https://github.com/ginowu7/CleanLocalizableExample

--

--