In Xcode 26 and later, String Catalogs can generate Swift accessors that replace manually typed localization keys. This guide migrates a small Mac app’s selection summary to typed properties and functions, then checks what the compiler actually protects.
The task is deliberately narrow: display a window heading and a summary containing two integer counts. All labels and values are synthetic. You will create the catalog contract, connect it to SwiftUI, and verify both compiler diagnostics and visible output.
What makes a localization accessor compile-time checked?
Apple introduced native String Catalog symbol generation in Xcode 26. An entry without placeholders produces a static property; an entry with placeholders produces a function with typed parameters. Both return LocalizedStringResource. New Xcode 26 projects enable generation by default; existing projects may need the build setting enabled. Code-along: Explore localization with Xcode
The useful change is at the call site. A string literal can spell a lookup key without referring to a Swift declaration. A generated accessor refers to a member that must exist, and a generated function requires arguments matching its signature. From those documented mechanics, the practical consequence is that a misspelled member or incompatible argument becomes a compiler error.
That protection has a specific scope. Swift can check that the accessor exists and that its arguments fit. It cannot determine whether the wording describes the intended interface, or whether two valid integer arguments represent the correct counts. Treat accessors as a checked programming interface to your messages.
Set up a small Mac app and its message contract
Use Xcode 26 or later and a macOS SwiftUI app target. For this example, set the deployment target to macOS 15 or later. The underlying LocalizedStringResource type is available from macOS 13; the example’s higher target is a prerequisite choice, not the minimum version of that type. A resource represents localizable text whose lookup can be deferred until it is needed. LocalizedStringResource
Add a catalog through File > New > File from Template. Select String Catalog under Resource, name it Workbench, and include it in the app target. Apple documents that each catalog represents a table; using a separate table here keeps the example’s two messages together. Localizing and varying text with a string catalog
In the project editor, open Build Settings, filter for Generate String, and set Generate String Catalog Symbols to Yes for the target’s effective configuration. This is the documented switch for older projects. Using generated localizable symbols in your code
Select the English source localization in Workbench.xcstrings. Add these two entries using the catalog editor’s toolbar + button. The comments define what the messages mean, including the roles of their arguments.
| Key | English source value | Comment |
|---|---|---|
TITLE |
Selection overview |
Heading above the selection summary. |
SUBTITLE |
%1$(selectedCount)lld selected; %2$(availableCount)lld available |
Selection summary. selectedCount is the number selected; availableCount is the total number available, including selected items. |
For SUBTITLE, you can enter each placeholder through Xcode’s completion menu: type %, choose the integer placeholder, and name it selectedCount or availableCount. Apple documents named variables and generated parameters for these format specifiers. Select each entry and inspect Generate Swift Symbol and Example Usages in the Attributes inspector. Using generated localizable symbols in your code
The intended contract is a title property and a subtitle function accepting two Int values. Check the inspector’s actual generated spelling before continuing: Apple says symbol names use both the key and its value. The examples below use .Workbench.title and .Workbench.subtitle(selectedCount:availableCount:), following Apple’s documented uppercase-key pattern. Code-along: Explore localization with Xcode
This contract makes a useful distinction explicit: availableCount includes selected items. Without that comment, a caller might reasonably interpret it as the number remaining. Both interpretations would type-check, so documenting the meaning is part of making the accessor useful.
Use the generated accessors in a complete window
After creating the catalog, choose Product > Build. Replace the template app declaration and content view with the following program, keeping exactly one @main declaration in the target. The catalog is a required resource for this program; pasting the Swift into a standalone file does not generate its accessors.
import Foundation
import SwiftUI
@main
struct SelectionOverviewApp: App {
var body: some Scene {
WindowGroup {
SelectionOverviewView(
selectedCount: 3,
availableCount: 12
)
}
}
}
struct SelectionOverviewView: View {
let selectedCount: Int
let availableCount: Int
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text(.Workbench.title)
.font(.title2)
Text(
.Workbench.subtitle(
selectedCount: selectedCount,
availableCount: availableCount
)
)
}
.padding(24)
.frame(minWidth: 360, minHeight: 140)
}
}
With the English source localization active, the illustrative inputs should display Selection overview followed by 3 selected; 12 available. The counts are fixed so that you can check argument placement without introducing selection-management code.
Apple documents generated resources as usable in SwiftUI, including Text, and through Foundation’s String(localized:) initializer. If an existing Mac interface requires a resolved String, convert the generated resource at that boundary. Code-along: Explore localization with Xcode
For example, this is a complete helper function to add to the same app target after the catalog exists:
import Foundation
func selectionSummary(
selectedCount: Int,
availableCount: Int
) -> String {
String(
localized: .Workbench.subtitle(
selectedCount: selectedCount,
availableCount: availableCount
)
)
}
Returning LocalizedStringResource from your own interface preserves a resource for later lookup; returning String resolves it when the initializer runs. Choose based on what the receiving interface needs. Apple describes this deferred-versus-immediate lookup distinction in the Foundation documentation. LocalizedStringResource
The examples were inspected against the retrieved documentation. They were not compiled here because the available environment has no Swift executable or Xcode.
Why the leading dot and argument labels matter
The leading dot is Swift’s implicit member syntax. It abbreviates access to a type member when the surrounding context lets Swift infer the type. It is ordinary Swift syntax, rather than a special string-key operator. Expressions — Implicit Member Expression
For generated localization symbols, the default Localizable table exposes members directly, while a named table introduces a table namespace. That is why this example includes .Workbench before the member name. Apple documents both forms. Using generated localizable symbols in your code
The labels selectedCount: and availableCount: belong to the function call. Swift distinguishes argument labels, which appear at the call site, from parameter names used inside a function. When a parameter requires a label, the caller must supply it. Functions — Function Argument Labels and Parameter Names
Readable labels help prevent mistakes, but both arguments here have the same type. Swapping the two integer values remains valid Swift. The message contract and the visible-output check therefore complement the compiler.
Migrate existing keys without losing their meaning
For existing localizable strings, Apple provides a refactoring workflow. Select entries in the String Catalog, Control-click, and choose Refactor > Convert Strings to Symbols. Inspect the preview, adjust the proposed symbol or parameter names if needed, and choose Convert. Using generated localizable symbols in your code
Migrate one coherent group first, such as the heading and summary for this window. Before accepting the preview, compare the old message and new contract: do they use the same table, describe the same interface element, and assign the same meaning to every placeholder? Review any existing localized values affected by a key change rather than assuming the refactoring proves their correctness.
For a call site the refactoring does not update, use the catalog inspector’s generated usage and replace that reference explicitly. Then build and inspect the resulting text. Avoid deleting the old entry until you have accounted for its callers.
If your installed Xcode lacks native generation, this workflow requires a newer toolchain. Apple also supports extracting strings from localizable APIs into catalogs, and recommends extraction as a starting workflow. It remains a supported way to manage localization, but it does not itself supply the generated-accessor contract described here. Code-along: Explore localization with Xcode
Verify the migration with a small diagnostic sequence
Use the following checks on the sample window. They separate compiler protection from message correctness and resource integration.
- Build the unchanged example to establish a working baseline.
- Temporarily misspell the title member and build. The nonexistent member should produce a compiler diagnostic. Restore it.
- Temporarily pass a
Stringvalue where the subtitle requires anInt. Build to check the type mismatch, then restore the integer. - Run with
selectedCountset to3andavailableCountset to12. Confirm the numbers occupy their intended positions. - Change only the catalog title value to
Current selection, rebuild, and confirm the displayed heading. Check that the generated signature remains the one your code uses.
If a member is missing unexpectedly, inspect the catalog entry’s generated usage first. Then check the generation setting, the catalog’s target membership, and the table name. A compiler diagnostic identifies a failed reference; these checks help distinguish a spelling error from an unavailable generated declaration.
Finally, test the actual interface. Apple’s documented route is Product > Scheme > Edit Scheme, then Run > Options, where you can select App Language before running. Repeat for the localizations your project supports. Testing localizations when running your app
For an early layout check, Xcode also offers Double-Length Pseudolanguage, which expands localizable text to reveal sizing problems. Inspect the summary at a narrow window width; successful compilation cannot establish whether the text fits. Test localizations
A finished migration gives each call site a real Swift member, gives each variable a documented role, and preserves a checked route to the intended catalog entry. Keep the compiler checks and the window checks together: the former validate the accessor contract, while the latter confirm that the reader sees the intended message.
Sources
LocalizedStringResource — Apple
Expressions — The Swift Programming Language
Functions — The Swift Programming Language
Test localizations — Apple