---
title: "How do I use variables in a localized string in Swift?"
description: "Interpolate the value inside `String(localized:)` (iOS 15 and later) or a SwiftUI `Text` literal; Xcode stores the key with a `%@` or `%lld` placeholder that translators keep. On older targets, combine `NSLocalizedString` with `String.localizedStringWithFormat`."
category: ios
date: 2026-10-09
canonical: https://localizely.com/i18n-questions/ios/how-do-i-use-variables-in-a-localized-string-in-swift/
---

# How do I use variables in a localized string in Swift?

Interpolate the variable inside `String(localized:)`, available since iOS 15 and macOS 12, or inside a SwiftUI `Text` literal. The key Xcode extracts contains a format specifier in place of the value, and the translation keeps that specifier.

```swift
let name = "Ana"
let count = 3

let greeting = String(localized: "Hello, \(name)!")
let summary = String(localized: "You have \(count) new messages")
```

When you build, Xcode adds `Hello, %@!` and `You have %lld new messages` to the String Catalog. A `String` becomes `%@`, an `Int` becomes `%lld` and a `Double` becomes `%lf`. The translator writes the words around the placeholder: `"¡Hola, %@!"`. The initializer is documented at [String(localized:table:bundle:locale:comment:)](https://developer.apple.com/documentation/swift/string/init(localized:table:bundle:locale:comment:)).

SwiftUI needs no extra call, because a string literal passed to `Text` is a `LocalizedStringKey`:

```swift
Text("Hello, \(name)!")   // looks up the key "Hello, %@!"
```

Before iOS 15, use `NSLocalizedString` for the format and substitute the values afterwards. Never interpolate inside the `NSLocalizedString` key: Xcode cannot extract it, and translators receive the code expression instead of the text.

```swift
let format = NSLocalizedString("Hello, %@!", comment: "Greeting with the user's name")
let greeting = String.localizedStringWithFormat(format, name)
```

`String.localizedStringWithFormat` formats numbers for the user's locale; `String(format:)` substitutes them without localizing.

Pitfalls:

- With two or more variables, a translator may need to change their order. Positional specifiers make that possible: the translation `"%2$lld messages from %1$@"` takes the same arguments as the source `"%@ sent %lld messages"`. The numbers refer to the interpolations in source order.
- The type in the specifier must stay the same in every translation; a `%@` replaced by `%d` can crash the app.
- `String(localized:)` searches the main bundle by default; pass `bundle:` for strings that live in a framework or package.
- A count that changes the sentence between singular and plural needs a plural rule, not two strings; see [How do I localize plurals in an iOS app?](/i18n-questions/ios/how-do-i-localize-plurals-in-an-ios-app/).

Source: https://localizely.com/i18n-questions/ios/how-do-i-use-variables-in-a-localized-string-in-swift/
