With the world being a global marketplace these days, the capacity of your mobile applications to be in different languages and cultures is not just an option but it is a necessity. Localization enchances the user experience, extends its reach and may have a great impact on the success of software on the international level.
For the iOS developers, Swift offers powerful tools to easily incorporate localization to the applications. This guide explains the transition in localization in Swift, from the early techniques to the latest tool, to help developers fully take advantage of these capabilities.
Initially, when Swift was first introduced, it inherited the localization infrastructure from Objective-C, which was built around the Localizable.strings
file and the NSLocalizedString
function. In this way, developers had to deal with editing the localized strings manually and synchronize them across different language files, a process that is both prone to errors and time-consuming.
Localizable.strings
The Localizable file is a simple key-value pair file where the strings are stored in a "key" = "value" format, where "key" is the code identifier and "value" is the localized string that the user will see. This file needs to be duplicated and translated to each supported language and put into the proper corresponding ‘.lproj’ directories, such as ‘en.lproj’ for English language and ‘de.lproj’ for German language.
Localizable.strings
Entry:"hello_world_key" = "Hello, World!";
In the Swift code, this string could be retrieved as:
let greeting = NSLocalizedString("hello_world_key", comment: "The default greeting")
The NSLocalizedString function makes it easier to access localized content by using keys from Localizable.strings
.
This function takes a key, provides a fallback value, and puts a comment for translators. Offering a comment is crucial as it gives translators the subtext to improve the accuracy and suitability of the translations.
Example: Greeting a user based on the time of day:
func greetingBasedOnTime() -> String {
let hour = Calendar.current.component(.hour, from: Date()) let key = hour < 12 ? "good_morning_key" : "good_evening_key" return NSLocalizedString(key, comment: "Greeting based on time of day")
}
With corresponding Localizable.strings
, entries looking like:
"good_morning_key" = "Good morning!";
"good_evening_key" = "Good evening!";
Here are some challenges with Localizable. strings that you might face:
1) Scalability Issues.
As the number of strings grows, it becomes tough to handle them. Managing multiple .strings files over time becomes cumbersome.
2) Duplication.
Each language required a separate file, leading to potential inconsistencies and duplicated efforts in managing strings. With one language to support, it might not be a problem but when you need to manage multiple languages, it sometimes becomes too troublesome.
3) Lack of Context.
However, the comments could be added in NSLocalizedString – even if they do not always help the translator to understand the context fully, that could result in inaccuracies in translation. Developers are often too lazy to fill them properly.
stringsdict
for PluralizationThe introduction of stringsdict
files brought a significant improvement for Swift localization, which primarily addressed the problems of pluralization. The main cause is that plurals of languages are formed differently, and what might be effective for English might not be for other languages such as Russian or Arabic.
Before the stringsdict
introduction, it was very difficult to manage them. stringsdict
enables programmers to determine rules for the categories like “one”, “few”, “many” and “other”, which ensure the same level of correctness in translation across languages.
Understanding stringsdict
files
Stringsdict
file is an XML property list, which is used to create strings that are localized depending on numeric values. This functionality is intended to correctly process plural forms because different languages have their own differing rules for processing plural forms.
Structure of a stringsdict
file:
A sample of stringsdict
file includes entries of all strings that need to be pluralized. Each entry comprises of a key and a dictionary in which the user defines one or more subkeys representing different plural categories.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>numberOfSongs</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@songs@</string>
<key>songs</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>one</key>
<string>One song</string>
<key>other</key>
<string>%d songs</string>
</dict>
</dict>
</dict>
</plist>
Example of using stringsdict
for pluralization
Let’s suppose we have an application that shows the number of articles that have been read by a user. On the screen, it should show a message presenting the correct plural form of the number of articles read.
Localizable.stringsdict
for English and Polish:
<!-- English -->
<key>article_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@articles@</string>
<key>articles</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>one</key>
<string>One article</string>
<key>other</key>
<string>%d articles</string>
</dict>
</dict>
<!-- Polish -->
<key>article_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@articles@</string>
<key>articles</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>one</key>
<string>Jeden artykuł</string>
<key>few</key>
<string>%d artykuły</string>
<key>many</key>
<string>%d artykułów</string>
<key>other</key>
<string>%d artykułu</string>
</dict>
</dict>
Here, the Polish localization clearly demonstrates the complexity of plural forms in some languages, where multiple plural categories (one, few, many, other) are needed to be used to correctly represent different numeric contexts.
Swift Implementation:
The stringsdict
entries can be utilized in the code by simply referring to the keys defined in the file when calling NSLocalizedString
.
let count = getArticleCount()
let formatString = NSLocalizedString("article_count", comment: "Count of articles read by a user")
let message = String(format: formatString, count)
This approach allows you to adaptively modify the output string to match the grammatic for the supported languages; all of this only in one line of code.
Benefits of stringsdict
One of the new features that were introduced with Xcode 15 is String Catalogs which are supposed to help developers make iOS and macOS applications localize even easier than before. While Localizable.strings
and stringsdict
have been helpful resources for storing and organizing strings, the String Catalogs are far more cohesive and more UI friendlier to manage localized strings.
These are the main aspects which should be highlighted in the string catalogs:
stringsdict
by offering finer control of plural forms, and text with variations depending on UI elements and device types.Swift Implementation:
Let’s suppose, that in a messaging application, you have to inform users about the number of messages that are unread by them. The notification has to be dynamic by showing the number of received messages and should adjust accordingly to the content type.
Step-by-Step Setup:
Create a String Catalog: Add a new String Catalog to your project. This will generate a .stringcatalog
file.
Add Entries: Use the editor to add entries for each string that needs to be localized. Then specify keys, default values, and any plural rules or adaptive parameters for each entry.
Localize Content: Provide translations for each supported language, specifying different forms for plurals, adaptations for device types, etc.
Implement in Code: Reference these strings using localized identifiers in your Swift code.
<!-- String Catalog Entry -->
<key>unread_messages_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@messages@</string>
<key>messages</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>one</key>
<string>You have one unread message.</string>
<key>other</key>
<string>You have %d unread messages.</string>
</dict>
</dict>
You could access this string like so:
let unreadCount = fetchUnreadMessagesCount()
let message = NSLocalizedString("unread_messages_count", value: "You have \(unreadCount) unread messages.", comment: "Notify about unread messages")
print(message)
While String Catalogs offer significant improvements, they also come with challenges. First, it is a learning curve; it takes time to get accustomed to a new system or way of creating something. Another potential challenge that developers could face is linked to the time and adjustments needed to integrate String Catalogs into existing projects where traditional localization files were already created and in use.
String Catalogs in Swift are the most recent further improvement of localization technology providing tools that are not only powerful but also flexible and user-friendly. By adding the technology as a part of the development lifecycle, the teams will have drastically improved efficiency and quality in the localization process; hence, better global products will be created.
I will be constantly updating this article with the latest developments in Swift localization tools. If you feel like I left anything out or you have thoughts about what I said, you can share them in the comments box below. Make sure to follow me for more interesting information and latest news!