Early Days: Hardcoding Strings

Localization in app development is the process of adapting the app to different languages and regions, making it accessible to a global audience. Swift, Apple’s powerful programming language, has seen significant advancements in localization techniques over the years. This article delves into the evolution of localization in Swift, from the traditional use of strings to the modern implementation of string catalogs. We’ll explore the various methods and provide coding examples to illustrate these concepts.

In the early days of app development, localization often involved hardcoding strings directly into the app’s code. This approach was simple but not scalable. Any change in the text required a code change, making it difficult to manage and prone to errors.

swift

// Example of hardcoded strings
let welcomeMessage = "Welcome to our app!"
print(welcomeMessage)

This method did not support localization, as all strings were embedded directly within the source code. Developers had to manually replace strings for different languages, leading to maintenance nightmares.

NSLocalizedString: The First Step Towards Localization

To address the challenges of hardcoding strings, Apple introduced NSLocalizedString. This macro allows developers to fetch localized strings from a Localizable.strings file. This file contains key-value pairs, where the key is a unique identifier and the value is the translated string.

Localizable.strings

The Localizable.strings file contains entries like this:

plaintext

/* Welcome message */
"welcome_message" = "Welcome to our app!";

Usage in Code

In the Swift code, you use NSLocalizedString to fetch the localized string:

swift

// Fetching localized string
let welcomeMessage = NSLocalizedString("welcome_message", comment: "Welcome message")
print(welcomeMessage)

This approach separated the code from the actual text, making it easier to manage and update translations. However, it still required careful management of string keys and values.

Base Internationalization: Simplifying Interface Localization

Base Internationalization introduced a more streamlined way to localize user interfaces. Instead of managing individual string files for each language, developers could now use a base storyboard or xib file that gets translated automatically.

Base Storyboard

The base storyboard file contains the default language’s text. Xcode then generates strings files for each language, which can be translated.

xml

<!-- Example from Main.storyboard -->
<textField id="welcomeTextField">
<rect key="frame" x="20" y="20" width="200" height="40"/>
<text key="placeholder" id="welcome_message">Welcome to our app!</text>
</textField>

Generated Localizable Files

The localization files for other languages are automatically generated and updated based on the base storyboard.

plaintext

/* German (de) translation */
"welcome_message" = "Willkommen in unserer App!";

Base Internationalization reduced the complexity of managing translations for user interface elements, but it still left room for improvement in handling dynamic and non-UI strings.

String Resources: Structured Localization

With the introduction of string resources, Swift developers gained a more structured approach to managing localized strings. This method involves creating structured string files, such as Localizable.stringsdict, which supports pluralization and other advanced features.

Localizable.stringsdict

The Localizable.stringsdict file provides a way to define string variants based on different rules, such as pluralization.

xml

<dict>
<key>welcome_message</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@message@</string>
<key>message</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Welcome to our app! You have one message.</string>
<key>other</key>
<string>Welcome to our app! You have %@ messages.</string>
</dict>
</dict>
</dict>

Usage in Code

Using the Localizable.stringsdict file in code involves the same NSLocalizedString method, but it fetches the correct variant based on the specified rules.

swift

// Fetching localized string with pluralization
let messageCount = 5
let welcomeMessage = String.localizedStringWithFormat(NSLocalizedString("welcome_message", comment: "Welcome message with count"), messageCount)
print(welcomeMessage)

This approach provides more flexibility and control over localized strings, especially for complex scenarios like pluralization.

SwiftGen: Automation and Safety

Managing localization keys manually can still be error-prone. Tools like SwiftGen automate this process, generating Swift code for accessing localized strings safely and efficiently.

SwiftGen Configuration

SwiftGen can be configured to scan your localization files and generate Swift code. The configuration is done through a YAML file.

yaml

strings:
inputs:
- Resources/en.lproj/Localizable.strings
outputs:
templateName: structured-swift4
output: Sources/Strings+Generated.swift

Generated Code

SwiftGen generates code that provides type-safe access to localized strings.

swift

// Generated by SwiftGen
enum L10n {
static let welcomeMessage = L10n.tr("Localizable", "welcome_message")
}
extension L10n {
private static func tr(_ table: String, _ key: String, _ args: CVarArg…) -> String {
let format = Bundle.main.localizedString(forKey: key, value: nil, table: table)
return String(format: format, locale: Locale.current, arguments: args)
}
}

Usage in Code

Using the generated code makes accessing localized strings safer and more efficient.

swift

// Accessing localized string using SwiftGen
let welcomeMessage = L10n.welcomeMessage
print(welcomeMessage)

SwiftGen reduces the risk of runtime errors due to missing keys or incorrect string formats, improving the overall robustness of the localization process.

String Catalogs: The Modern Approach

With iOS 13, Apple introduced string catalogs (.stringsdict files) as a new way to manage localized strings. String catalogs provide a more organized and scalable approach to localization.

Creating a String Catalog

String catalogs are created as .xcstrings files within Xcode. These files allow you to organize localized strings hierarchically.

plaintext

/* Example String Catalog structure */
- Localizable.xcstrings
- en.lproj
- Localizable.strings
- de.lproj
- Localizable.strings

Adding Strings

Adding strings to a string catalog involves defining keys and their corresponding translations in each language’s .strings file.

plaintext

/* en.lproj/Localizable.strings */
"welcome_message" = "Welcome to our app!";
/* de.lproj/Localizable.strings */
“welcome_message” = “Willkommen in unserer App!”;

Using String Catalogs in Code

Accessing strings from a string catalog in code is similar to using NSLocalizedString, but with added organization and scalability.

swift

// Fetching localized string from a string catalog
let welcomeMessage = NSLocalizedString("welcome_message", tableName: "Localizable", bundle: .main, value: "", comment: "Welcome message")
print(welcomeMessage)

String catalogs simplify the management of large sets of localized strings, making it easier to organize and maintain translations.

Conclusion

The evolution of localization in Swift has seen significant improvements, from hardcoding strings to using sophisticated string catalogs. Each step in this journey has aimed to simplify and streamline the localization process, making it more efficient and less error-prone. Today, with tools like SwiftGen and features like string catalogs, developers can manage localized strings in a structured, scalable, and safe manner. As Swift and the iOS ecosystem continue to evolve, we can expect even more advanced and user-friendly localization techniques to emerge, further enhancing the global reach and user experience of apps.

Localization is a critical aspect of app development that enables apps to cater to a diverse, global audience. By understanding and utilizing the latest localization techniques in Swift, developers can create apps that are not only functional and beautiful but also accessible and enjoyable for users around the world.