NSLocalizedString
Swift programming
Swift localization
Swift variables
iOS development

How to use NSLocalizedString function with variables in Swift?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

NSLocalizedString retrieves translated strings from .strings files for localization. When the translated text includes dynamic values like a username, count, or date, you combine NSLocalizedString with String(format:) to insert variables into placeholders (%@ for strings, %d for integers, %.2f for floats). Swift 5.5+ also provides String(localized:) which supports string interpolation directly. Proper use of format specifiers and .stringsdict files for pluralization ensures translations work correctly across all languages.

Basic NSLocalizedString with Variables

swift
1// Localizable.strings (English)
2// "welcome_message" = "Hello, %@! Welcome back.";
3// "items_count" = "You have %d items in your cart.";
4
5let username = "Alice"
6let greeting = String(
7    format: NSLocalizedString("welcome_message", comment: "Greeting with username"),
8    username
9)
10// "Hello, Alice! Welcome back."
11
12let count = 3
13let itemsMessage = String(
14    format: NSLocalizedString("items_count", comment: "Number of cart items"),
15    count
16)
17// "You have 3 items in your cart."

NSLocalizedString returns the localized format string. String(format:) substitutes the placeholders with the provided values. The comment parameter helps translators understand the context.

Format Specifiers

swift
1// Localizable.strings
2// "price_label" = "Total: $%.2f";
3// "progress" = "Step %d of %d";
4// "user_info" = "%@ has %d followers (%@ joined)";
5
6// Float with 2 decimal places
7let price = 49.99
8let priceLabel = String(
9    format: NSLocalizedString("price_label", comment: "Price display"),
10    price
11)
12// "Total: $49.99"
13
14// Multiple integers
15let current = 3
16let total = 10
17let progress = String(
18    format: NSLocalizedString("progress", comment: "Step progress"),
19    current, total
20)
21// "Step 3 of 10"
22
23// Mixed types
24let info = String(
25    format: NSLocalizedString("user_info", comment: "User profile info"),
26    "Alice", 1500, "2023"
27)
28// "Alice has 1500 followers (2023 joined)"
SpecifierTypeExample
%@String (NSObject)"Alice"
%dInt42
%fDouble/Float3.14159
%.2fFloat (2 decimals)3.14
%ldLong Int1000000
%%Literal %%

Positional Arguments for Reordering

swift
1// English: "From %1$@ to %2$@"
2// German:  "Von %1$@ nach %2$@"
3// Japanese: "%2$@まで%1$@から"  (order reversed!)
4
5// Localizable.strings (English)
6// "route" = "From %1$@ to %2$@";
7
8// Localizable.strings (Japanese)
9// "route" = "%2$@まで%1$@から";
10
11let route = String(
12    format: NSLocalizedString("route", comment: "Route from origin to destination"),
13    "Tokyo", "Osaka"
14)
15// English: "From Tokyo to Osaka"
16// Japanese: "Osakaまで Tokyoから"

Positional specifiers (%1$@, %2$@) allow translators to reorder arguments without changing the code. This is essential because word order varies between languages.

Pluralization with .stringsdict

xml
1<!-- Localizable.stringsdict -->
2<?xml version="1.0" encoding="UTF-8"?>
3<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
4    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5<plist version="1.0">
6<dict>
7    <key>photos_count</key>
8    <dict>
9        <key>NSStringLocalizedFormatKey</key>
10        <string>%#@count@</string>
11        <key>count</key>
12        <dict>
13            <key>NSStringFormatSpecTypeKey</key>
14            <string>NSStringPluralRuleType</string>
15            <key>NSStringFormatValueTypeKey</key>
16            <string>d</string>
17            <key>one</key>
18            <string>%d photo</string>
19            <key>other</key>
20            <string>%d photos</string>
21        </dict>
22    </dict>
23</dict>
24</plist>
swift
1let count = 1
2let message = String(
3    format: NSLocalizedString("photos_count", comment: "Photo count"),
4    count
5)
6// count=1: "1 photo"
7// count=5: "5 photos"

.stringsdict files handle pluralization rules that vary by language. Russian has different forms for 1, 2-4, and 5+ items. Arabic has six plural forms. The .stringsdict file handles this automatically.

Swift 5.5+ String(localized:)

swift
1// Modern Swift approach (iOS 15+)
2let name = "Alice"
3let count = 3
4
5// String interpolation works directly
6let greeting = String(localized: "Hello, \(name)! You have \(count) items.")
7
8// With explicit table and bundle
9let message = String(
10    localized: "welcome_\(name)",
11    table: "Greetings",
12    bundle: .main,
13    comment: "Welcome message with name"
14)
15
16// The key in Localizable.strings uses the interpolation pattern
17// Localizable.strings:
18// "Hello, %@ ! You have %lld items." = "Hello, %@! You have %lld items.";

String(localized:) is the modern replacement for NSLocalizedString. It supports string interpolation and generates the .strings keys automatically from the interpolation pattern.

Common Pitfalls

  • Using %d for large numbers on 64-bit systems: On 64-bit platforms, Int is 64 bits. Using %d (32-bit) with a Swift Int causes undefined behavior. Use %ld or %lld for Int values, or use %@ with NSNumber wrapping. String(localized:) handles this automatically.
  • Hardcoding argument order without positional specifiers: "From %@ to %@" assumes arguments always appear in the same order. Translators for languages with different word orders cannot reorder the arguments. Always use positional specifiers (%1$@, %2$@) in localizable strings.
  • Forgetting to add the comment parameter: The comment in NSLocalizedString("key", comment: "...") is shown to translators to explain context. Without it, translators may misinterpret %@ placeholders and produce incorrect translations.
  • Not using .stringsdict for plurals: Appending "s" conditionally (count == 1 ? "item" : "items") only works for English. Languages like Russian, Arabic, and Polish have multiple plural forms. Always use .stringsdict for count-dependent strings.
  • Testing only in English: Format strings that work in English may break in other languages where arguments are reordered or where number formatting differs (comma vs period for decimals). Test localization with at least one right-to-left language and one language with complex plural rules.

Summary

  • Use String(format: NSLocalizedString("key", comment: "..."), args) to insert variables into localized strings
  • Format specifiers: %@ (string), %d (int), %.2f (float), %ld (long int)
  • Use positional specifiers (%1$@, %2$@) to allow translators to reorder arguments
  • Use .stringsdict files for proper pluralization across languages
  • On iOS 15+, use String(localized:) for cleaner syntax with string interpolation
  • Always provide meaningful comments for translators

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.