Handling Format Specifiers in Translations

Why %@ and %lld matter, and how XCStrings Translator keeps them intact across languages.

Format specifiers are the %@ and %lld placeholders in your strings. They get replaced with actual values at runtime. Mess them up, and your app crashes. Get them right, and dynamic content flows naturally in every language.

Swift
Text("Hello, \(name)!")
Text("\(count) items remaining")
Text("\(sender) sent \(recipient) a message")
↓ Xcode extracts as
Key
Source
Translation
State
Hello, %@!
Hello, %@!
Hallo, %@!
Translated
%lld items remaining
%lld items remaining
Translated
one
%lld item remaining
%lld Artikel übrig
Translated
other
%lld items remaining
%lld Artikel übrig
Translated
%1$@ sent %2$@ a message
%1$@ sent %2$@ a message
%2$@ erhielt eine Nachricht von %1$@
Translated

What Are Format Specifiers?#

When you write SwiftUI code like this:

Text("Hello, \(name)!")
Text("\(count) items remaining")

Xcode extracts these as localized strings with format specifiers:

"Hello, %@!"
"%lld items remaining"

At runtime, the %@ becomes "John" and the %lld becomes "5". The specifiers are placeholders that your code fills in.

Common Specifiers#

SpecifierTypeExample
%@String/Object"Hello, %@""Hello, John"
%lldInteger (64-bit)"%lld items""5 items"
%dInteger (32-bit)"%d items""5 items"
%fFloat/Double"%.2f miles""3.14 miles"
%%Literal %"100%% complete""100% complete"

The %@ specifier is the workhorse—it handles strings, numbers, and any object that conforms to CustomStringConvertible.

The Danger Zone#

If a translator accidentally removes, duplicates, or changes a format specifier, your app crashes. Or worse—it silently corrupts data.

Source:  "Hello, %@!"
Bad:     "Hallo!"          // Missing %@ → crash
Bad:     "Hallo, %@%@!"    // Extra %@ → crash
Bad:     "Hallo, %d!"      // Wrong type → undefined behavior

This is why translation tools need to validate format specifiers. A human translator might not notice a missing %@. A good tool catches it immediately.

Positional Arguments#

What if a sentence needs to be reordered in another language?

English: "John sent Sarah a message"
German:  "Sarah erhielt eine Nachricht von John"

With simple %@ specifiers, this doesn't work—they're replaced in order. The solution is positional arguments:

Source:  "%1$@ sent %2$@ a message"
German:  "%2$@ erhielt eine Nachricht von %1$@"

The %1$@ means "first argument" and %2$@ means "second argument". Translators can reorder them freely.

XCStrings Translator handles positional arguments correctly. When translating a string with %1$@ and %2$@, the AI knows to preserve the position numbers even if word order changes.

Plurals and Specifiers#

Plural strings almost always have format specifiers. The number that determines the plural form is usually also displayed:

Text("\(count) files selected")

This becomes a plural string with %lld:

{
  "one": "%lld file selected",
  "other": "%lld files selected"
}

Every plural variation needs the specifier. Forget it in one variation, and you'll get crashes for certain counts.

See Understanding Plural Rules for more on how plurals work.

How XCStrings Translator Helps#

XCStrings Translator validates format specifiers on every translation:

  1. Counts specifiers — Source has 2 specifiers? Translation needs exactly 2.
  2. Checks types — Source uses %@? Translation can't use %d.
  3. Validates positions%1$@ and %2$@ must both be present.
  4. Shows warnings — Before you save, you'll see any mismatches.

The AI models (GPT-4o, Claude) are explicitly instructed to preserve format specifiers. They're generally very good at it. But the validation catches any slip-ups before they reach your users.

Best Practices#

Use positional arguments for multiple placeholders. Even if English doesn't need reordering, another language might. %1$@ and %2$@ give translators flexibility.

Keep specifiers in translator comments. When adding a comment in Xcode, mention what each placeholder represents:

"upload_progress" = "%1$@ of %2$@ uploaded"
// Comment: %1$@ is current file name, %2$@ is total count

Test with edge cases. Empty strings, very long strings, zero, negative numbers. Make sure your format specifiers handle them all.

Review warnings before saving. XCStrings Translator shows warnings for mismatched specifiers. Don't ignore them—they usually indicate a real problem.

Ready to translate your app?

Download XCStrings Translator and start localizing your iOS and macOS apps with AI-powered translations.

Download for macOS