Arm1.ru

Localizing a Swift Package with a String Catalog

Recently, I've been working on a Swift Package with some strings that I wanted to localize. Apple's documentation on this topic seems to be a bit outdated. The documentation still suggests using language-specific directories for localizing resources and strings.

But, at WWDC 2023, Apple introduced String Catalogs. It's much more handy - just a JSON file that Xcode can fill with all the strings that need to be localized. Most of the examples you can find are about apps, not packages. So, I've spent some time trying to figure out how to use String Catalogs in a Swift package.

Good news - it's possible!. Let's start with an example Swift Package. Here's an example Package.swift file:

// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "SwiftPackageLocalized",
    platforms: [
        .iOS(.v15),
        .macOS(.v12),
    ],
    products: [
        .library(
            name: "SwiftPackageLocalized",
            targets: ["SwiftPackageLocalized"]),
    ],
    targets: [
        .target(
            name: "SwiftPackageLocalized"),
    ]
)

So, the first step is to add the defaultLocalization parameter:

let package = Package(
    name: "SwiftPackageLocalized",
    defaultLocalization: "en", // set the default localization
    …
)

Next step - add a Strings Catalog in Xcode (File → New → File from Template…):

Now we can add our Strings Catalog to resources processing in Package.swift. The final file will look like this:

// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "SwiftPackageLocalized",
    defaultLocalization: "en",
    platforms: [
        .iOS(.v15),
        .macOS(.v12),
    ],
    products: [
        .library(
            name: "SwiftPackageLocalized",
            targets: ["SwiftPackageLocalized"]),
    ],
    targets: [
        .target(
            name: "SwiftPackageLocalized",
            resources: [
                .process("Localizable.xcstrings")
            ]
        ),
    ]
)

Finally, we can use localized strings in our code:

let myString = String(
    localized: "MY_STRING",
    defaultValue: "Wow, a localized string!",
    bundle: Bundle.module
)

Build the package, and you will see that the Strings Catalog now has strings and is ready for localization to other languages:

In a next post I'll show how to add translations automatically with AI help.

keyboard_return back