Let’s immediately localize our projects

New project? Whether you need it or not, start localizing immediately. It does not matter that your app is only in English at launch, sooner or later, you’ll need to internationalize your app. So you’ll only see the benefits later, when you are app picks up and you suddenly find the need to translate it.

Good news, with a few simple tricks that can be started when the project is created or soon after:

  • you won’t have to open all your screens one by one to find what needs to be localized, it’s already done
  • you will find all localized strings in your catalog, ready to be sent to somebody for translation
  • bonus: if you work for a company, impress your boss by giving a ridiculously low estimate for how much time it will take to localize, the work was done incrementally, and it’s not going to be a huge project to support a new language

Add a String Catalog to your project

In the file explorer of Xcode, right-click in your Resources or Supporting Files folder, click “New File…”, and add a String Catalog called “Localizable”.

That’s it, you are ready to localize.

Adopt a naming convention for your keys

Keep it simple, my keys are always structured the same, with a bit of consistency, you will make it easy to find what you want, and maintain your project.

The convention I recommend is:

  • the first segment is the name of the screen
  • each segment gets more specific about where the string is going to be used and what it represents
  • each segment of your key is written using snake_case
  • segments are separated by a dot .

For example:

  • “editor.title” represents the title of the Editor screen
  • “editor.add_frame_button.title” represents the title within

Write a shorthand to transform a key into a localized string

Writing NSLocalizedString every time you need it and adding a comment isn’t. It’s dead simple, start by creating a new String+i18n.swift file.

Add a basic extension to transform a string into a localized string:

import Foundation

extension String {
    var i18n: String { NSLocalizedString(self, comment: "") }
}

And then to use it in code:

func viewDidLoad() {
    super.viewDidLoad()

    // i18n
    title = "editor.title".i18n // Editor
    addFrameButton.setTitle("editor.add_frame_button.title".i18n, forState: .normal) // Add Frame
}

And that’s pretty much it. Never hardcode an interface string and always use your shorthand function to localizable each and every string, it’s an overhead of approximately 30 seconds per screen that will benefit you in the long run. This will work with UIKit & SwiftUI.

Localize your app early

And when I say early, I mean immediately, as soon as you create your project. Trust me, just do it, take the few minutes it takes to setup localization and do it from the first word that will appear on your interface.

Regardless of your app supporting several languages at launch, doing so will not consume additional time, and these few moments will literally save you hours later on, when you actually have to translate the app.

Consistent keys

When adding a new localized key, I always group it with other keys of the same screen and use the same naming convention: snake case + name of the screen followed by a dot and followed by a description of what the key is, eg:

// EventList
"event_list.title" = "Events";
"event_list.new" = "Create Event";

There are many systems out there, find your own and stick to it.

Take shortcuts

Especially if you don’t have to, using NSLocalizedString(_:comment:) everywhere and in the proper way can be cumbersome. So unless your team and process requires it (and in most apps it will certainly not be required), you can take a small shortcut that will greatly help: build an extension to wrap the function and make the comment parameter optional.

//  String+i18n.swift

import Foundation

extension String {
    func i18n(comment: String = "") -> String {
        return NSLocalizedString(self, comment: comment)
    }
}

It’s makes it really to use by calling the i18n() method on the key.

class EventListViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // i18n
        title = "event_list.title".i18n()
    }
}

Automate

You are now supporting several languages, nice, it’s time to automate! Please don’t open the string file in each language to add your keys, this is the best way to make mistakes.

Instead, for small to medium projects, you can easily create a shared document on Google Spreadsheet with a “key” column and a column for each supported language, and write a small script to download the sheet as a CSV file and generate one .string file per language.

Good habits makes your life easier

What if I’m doing a really quick and dirty test and don’t want to take the few seconds to write the localizable for it? I understand, and I do it sometimes, in this case, just make sure to:

  1. take note that this piece of code will need localization later
  2. be consistent so that you can retrieve all the places that need localization in one go.

I usually add a // TODO: i18n before or after the code using hard-coded text, it’s easy, and because I always use the same text in the comment, all the occurrences will show up in one project search.