2021 EssentialsSwiftUI & UI FrameworksSystem ServicesAccessibility & Inclusion
WWDC21 · 27 min · Essentials / SwiftUI & UI Frameworks / System Services / Accessibility & Inclusion
Streamline your localized strings
When you localize the text within your app, you can help make your app more accessible to a worldwide audience. Discover best practices for building your localization workflow, including how to write and format strings accurately, and learn how to prepare strings for localization in different languages using Xcode.
Watch at developer.apple.com ↗Code shown on screen · 20 snippets
Declaring a string
Button("Order") Declaring a string anywhere else
button.title = NSLocalizedString("Order", comment: "…")
button.title = String(localized: "Order") Declaring a string in a SwiftUI view 2
Text("Your order is ready.")
Button("Order") {
// Action…
} Declare a string in SwiftUI view with verbatim
Text(verbatim: "Sample data") Button to place an order
// SwiftUI
Button("Order") { … }
// Swift
button.title = String(localized: "Order") Button to place an order with a variable
let count = 3
// SwiftUI
Button("Order \(count) Tickets") { … }
// Swift
button.title = String(localized: "Order \(count) Tickets") Button to place an order with a variable 2
let count = 3
// Supports user’s preferred numbers,
// pluralization, RTL variables isolation…
// Previously: .localizedStringWithFormat()
String(localized: "Order \(count) Tickets") Use 2 separate strings
// Recommended for all languages
String(localized: "Order Now")
String(localized: "Order Later") Button to place an order 2
// SwiftUI
Text("Order")
// Swift
String(localized: "Order") Button to place an order with comment
// SwiftUI
Text("Order", comment: "Button: confirms concert tickets booking”)
// Swift
String(localized: "Order", comment: "Button: confirms concert tickets booking") What makes a good comment
Text("Order", comment: "Button: confirms concert tickets booking")
Text("Order", comment: "Button: confirms concert tickets booking")
Text("\(ticketCount) Ordered", comment: "Order summary: total number of tickets ordered") Request server strings in the user's language
Bundle.preferredLocalizations(from: allServerLanguages).first Declare a string with a variable, customized table name, and a comment
Text("\(ticketCount) Ordered",
tableName: "UserProfile",
comment: "Profile subtitle: total number of tickets ordered") Using a framework
/* —-----------—------------—-—---- In TicketKit Framework —---------—------------—-—---- */
// TicketKit/OrderStatus.swift
public enum OrderStatus {
case pending, processing, complete, canceled, invalid(Error)
var displayName: String {
switch self {
case .complete: return String(localized: "Complete",
bundle: Bundle(for: AnyClassInTicketKit.self),
comment: "Standalone ticket status: order finalized")
/* —-----------—-----------—---—--- In Host App —---------—------------—-—---- */
import TicketKit
Text(OrderStatus.complete.displayName) Import translated strings catalogs
xcodebuild -exportLocalizations -workspace VacationPlanet.xcworkspace -localizationPath ~/Documents
xcodebuild -importLocalizations -workspace VacationPlanet.xcworkspace -localizationPath ~/Documents/de.xcloc Localized attributed strings
AttributedString(localized: "Your order is **complete**!",
comment: "Ticket order confirmation title") Plural with stringsdict
String(localized: "Order \(ticketCount) Ticket(s)") Plural for strings without a number
if ticketCount == 1 {
button.text = String(localized: "Order This Ticket")
} else if ticketCount == 2 { // If needed
button.text = String(localized: "Order Both Tickets")
} else {
button.text = String(localized: "Order All Tickets")
} Automatic grammar agreement
AttributedString(localized: "Order ^[\(ticketsCount) Ticket](inflect: true)") Format data in strings
["pop", "rock", "electronic"].formatted(.list(type: .or)) // pop, rock, or electronic
Text("Total: \(price, format: .currency(code: "USD"))", // Total: $9.41
comment: "Order subtitle: total price of all tickets") Resources
Related sessions
-
34 min -
22 min -
38 min -
18 min -
15 min -
35 min