Sharing passion in Swift

#27 Localize your strings swiftly

Hey, long time no see! It’s because we’re working on two important issues, stay tuned! This issue will be short and it will show you how you can define and access localized version of your strings in a swift manner!

NSLocalizedString

In Xcode we can easily create a Localizable.strings file in which one can define pairs of key and value strings that can be used throughout our application. A sample file would look like this:

1

2

3

4

5

6

"Hello"="Hello";

"This application is created by the swifting.io team"="This application is created by the swifting.io team";

"Ops! It looks like this feature haven't been implemented yet :(!"="Ops! It looks like this feature haven't been implemented yet :(!";

If we wanted to create e.g. an Italian version of our app, we would have to create another Localizable.strings and put Italian version of strings (values). Just use ⌘⇧N (CMD + SHIFT + N) shortcut to create new file, type strings in filter field and select Strings File. Name the file Localizable.strings:

You can edit the file with localisations:

Once you decide on creating a translation, select project file in Project navigator and in Editor area. Go to Localizations section, tap + button and select a language:

Then select files you want to localize (only Localizable.strings in our case):

And start translating your strings :)!

You can check full tutorial from Ray Wenderlich linked in Resources section at the bottom of the post. The tutorial is for an ancient 😉 language called Objective-C, but yet it’s still one of my favourite languages (after Swift of course!).

Ok, we have those files, but what’s next? To use such strings we have to call NSLocalizedString(key:comment:) function:

1

2

3

4

letmyString=NSLocalizedString(key:"This application is created by the swifting.io team",comment:"")

Looks kinda ancient 😂. Do we really need this longNSLocalizedString(key:comment:) calls? And what’s the comment param, left here empty?

You can pass a hint for a translator inside this argument, e.g. NSLocalizedString(key:"Hello", comment: "This is the string shown on the first screen after app launch, to welcome the user"). The comment is used by Xcode when exporting files for localization, but more on that can be found in Apple’s Internationalization and Localization Guide.

But still, do I really need to use such approach in my Swift code 🐦 !?

Swiftier way

No, a swifter way exists. Thanks to extensions, we can extend types and classes with functions and static variables. Hence, we can extend String. But before that, let’s create a simpler version of NSLocalizedString(key:comment:) without comment param, in order not to type the empty comment hundreds of times throughout the file, if we don’t intend to use comment hints for our translations 👹.

1

2

3

4

5

6

fileprivate funcNSLocalizedString(_key:String)->String{

returnNSLocalizedString(key,comment:"")

}

We can mark this function as fileprivate so nobody would use this function unintentionally outside the file with our strings, but I can stay internal or public as well, doesn’t matter. Oh, btw. you can create a Strings+Localized.swift file in which your Swift strings can be kept. So what’s now?

Now we will extend the String type to include our localized versions of strings:

1

2

3

4

5

6

7

8

9

importFoundation

extensionString{

staticletHello=NSLocalizedString("Hello")

staticletThisApplicationIsCreated=NSLocalizedString("This application is created by the swifting.io team")

staticletOpsNoFeature=NSLocalizedString("Ops! It looks like this feature haven't been implemented yet :(!")

}

You can use such an approach even without Localizable.strings file at all, just to have in mind that your app might need translation in the future. Having such an extension on String allows you to use localized version of strings like this:

A few more tips on extending String

If you have a large app, your Strings+Localized.swift file can become large and unreadable. You can divide strings into multiple extension blocks and annotate them using //MARK::

1

2

3

4

5

6

7

8

9

10

11

//MARK: Login screen

extensionString{

//...

}

//MARK: Welcome screen

extensionString{

//...

}

You could even create a file for each screen, e.g. Strings+Login, Strings+Welcome.swift, but be aware that in rapid development it can be a hinder task to do and maintaining multiple files could become even trickier.

One more thing to note is that Strings defined in the described way are static strings. Your app should be relaunched after changing language in iOS Settings app. If not, relaunch it by yourself in order to see changes. It can also have a memory overhead, since we initialize all strings at once, not at the time they’re needed.

iOS localization projects can be managed more easily with the help a professional localization platform like https://poeditor.com
You can translate strings using various strategies: crowdsourcing, ordering translations, with your own inhouse translators, with automatic translation or using a combination of these.
It’s also a really good tool to automate the localization workflow (having an API and features like translation memory and integrations with code hosting platforms like GitHub).
I think you’ll find it useful.

Hello, nice article brother. Putting some static string to quickly access them while coding is nice, but how do you do if you have a special value you need to put? e.g “Yesterday you sold %@ apps” = “Yesterday you sold %@ apps”;

I would not recommend this approach, NSLocalizedString macro is used by Xcode when exporting localizations to .xliff (Editor -> Export for localization…), if you rename NSLocalizedString to something else Xcode won’t be able to recognize these strings and, you’ll have to manually manage .strings files yourself, which is barbaric

That’s true, thanks for sharing. The problem lays in usage of NSLocalizedString(:) instead of NSLocalizedString(:comment:). The solution is to replace our NSLocalizedString(:) with default version of the function (Swift) / macro (ObjC).