Highlight
SwiftUI complements localization capabilities in Text, LocalizedStringKey, Markdown, FormatStyle, keyboard shortcuts, and the Xcode 13 export process, allowing developers to leave strings, formats, and layouts to the system for processing, reducing manual corrections in multi-language adaptation.
Core Content
When many applications are localized for the first time, the problem lies in the details.
In the English interface, a button is written asDone, a label is written asIngredients, there seems to be no problem. When it comes to Russian, Arabic or Lithuanian, the text length, semantic context, writing direction, and keyboard layout all change.
In the past, developers often had to check for these changes themselves. Which strings can be exported to translators? WhichIngredientsWhich is the “ingredient” in the recipe? Which is the “ingredient” in the menu? How to display calorie units by region? Can shortcut keys be pressed on non-US keyboards? These problems can easily be delayed until release.
In this session, Apple used the Fruta sample application to demonstrate a new path: SwiftUI defaults toTextThe string literal is treated as a localization key; custom views can useLocalizedStringKeyKeep the same behavior; styles are left to Markdown; values are left to the new formatting API; layout and keyboard shortcuts are left to the system to automatically adapt.
Xcode 13 also changes the export process. When exporting localized content, Xcode can build the target and extract it through the Swift compilerLocalizedStringKey. Multi-line strings and strings in SwiftUI custom views can be entered into the localization catalog more accurately.
As a result, developers don’t need to write a UI for every language. You just expose the translatable content, give the translation enough context, and use the system to format the data, and SwiftUI will handle a lot of the language differences.
Detailed Content
String literals will automatically check the localization table
(01:34) SwiftUITextWhen receiving string literals, localized string lookup will be done in the main bundle. Button titles, labels, and prompt copy can all start here.
import SwiftUI
struct RewardsSheet: View {
let done: () -> Void
var body: some View {
Button(action: done) {
Text("Done", comment: "Button title to dismiss rewards sheet")
}
}
}
Key points:
Button(action: done)Use the incomingdoneThe closure closes the reward page. -Text("Done", comment: ...)BundleDoneExposed as a localizable string. -commentTo give context to the translation: This is the title of the button that closes the bonus sheet.- At runtime, SwiftUI looks up the corresponding translation from the bundle based on the current language.
(01:58) String interpolation will also be extracted. Xcode 13 infers the format specifier based on the type of the interpolated variable.
import SwiftUI
struct RewardsCard: View {
let totalStamps: Int
var body: some View {
Text("You are \(10 - totalStamps) points away from a free smoothie!")
}
}
Key points:
totalStampsIs the number of points the user has earned. -10 - totalStampsCalculate how far away you are from a free smoothie.- Interpolation expressions go into exported localized string files or catalogs.
- Xcode 13 based
IntType inference format placeholder to reduce manual writing errors%d、%@opportunity.
(02:06) The same English word may require different translations in different scenarios.Textcan passtableNamePut the string into a separate table.
import SwiftUI
struct IngredientHeaders: View {
var body: some View {
VStack(alignment: .leading) {
Text(
"Ingredients.recipe",
tableName: "Ingredients",
comment: "Ingredients in a recipe. For languages that have different words for \"Ingredient\" based on semantic context."
)
Text(
"Ingredients.menu",
tableName: "Ingredients",
comment: "Ingredients in a smoothie. For languages that have different words for \"Ingredient\" based on semantic context."
)
}
}
}
Key points:
- Both strings are placed in
IngredientsThe table and the inside make it easy to manage the same type of copywriting. -Ingredients.recipeUsed in recipe context. -Ingredients.menuUsed in smoothie menu context. -commentTell the translator explicitly: Some languages choose different words based on semantic context.
Custom SwiftUI view needs to receive LocalizedStringKey
(02:52) The problem often occurs with custom views. you putStringPassed to the component and then handed to it inside the componentText, Xcode may not be able to treat this literal as a SwiftUI localization key.
The solution is to change the parameter type toLocalizedStringKey。
import SwiftUI
struct Card: View {
var title: LocalizedStringKey
var subtitle: LocalizedStringKey
var body: some View {
Circle()
.fill(BackgroundStyle())
.overlay(
VStack(spacing: 16) {
Text(title)
Text(subtitle)
}
)
}
}
struct OrderCompleteView: View {
var body: some View {
Card(
title: "Thank you for your order!",
subtitle: "We will notify you when your order is ready."
)
}
}
Key points:
titleandsubtitleuseLocalizedStringKey, retaining the localized semantics of SwiftUI. -Text(title)andText(subtitle)Read translations from bundle at runtime. -Card(...)The string literal is still passed to the calling site, and the writing method remains unchanged.- When Xcode exports localized content, it can be extracted and passed to
Cardtitle and subtitle.
(03:47) Xcode 13 can use the compiler when exporting localized content. Multi-line strings are also parsed correctly.
import SwiftUI
struct SmoothieDescription: View {
var body: some View {
Text("""
A delicious blend of tropical fruits and blueberries will
have you sambaing around like you never knew you could!
""",
comment: "Tropical Blue smoothie description")
}
}
Key points:
- Triple quotes declare multi-line strings, suitable for longer description copy.
-
TextStill receive localizable content. -commentMark this description as Tropical Blue smoothie. - Xcode 13 uses the Swift compiler to extract strings and reduce multi-line text parsing failures.
The layout supports longer text and right-to-left languages by default
(04:12) After localization, the text usually becomes longer. SwiftUI controls will makeTextWrap lines to avoid direct cutting.
(04:26) Right-to-left language also affects layout direction. SwiftUI flips the table cell layout and mirrors tab bar symbols when appropriate.
Developers need to avoid hardcodingleftandright. Apple highlighted in its presentationleadingThis direction has nothing to do with writing.
import SwiftUI
struct SmoothieSummary: View {
let smoothieTitle: LocalizedStringKey
let ingredients: LocalizedStringKey
var body: some View {
VStack(alignment: .leading) {
Text(smoothieTitle)
.font(.headline)
Text(ingredients)
}
}
}
Key points:
VStack(alignment: .leading)Use semantic orientation.- In left-to-right languages,
leadingUsually corresponds to the left side. - In right-to-left languages, the system can
leadingMap to the other side. -TextResponsible for displaying the localized smoothie name and ingredient text.
Markdown lets translation determine the style placement
(05:13) SwiftUITextLocalized strings with Markdown can be displayed directly. The point of doing this is to put the style and translation in the same string.
import SwiftUI
struct LemonberryDescription: View {
var body: some View {
Text(
"A refreshing blend that's a *real kick*!",
comment: "Lemonberry smoothie description"
)
}
}
Key points:
*real kick*Use Markdown emphasis.- Strings are still exported as localized content.
- Translation can adjust emphasized words according to the target language.
- SwiftUI directly renders styled
Text, no need to split multiple text fragments.
FormatStyle handles localized values directly
(06:04) Prior to iOS 15, Fruta needed to createMeasurementFormatter, and then convert the calories into a string.
import Foundation
import SwiftUI
struct LegacyCaloriesView: View {
let nutritionFactKilocalories: Double
static let measurementFormatter: MeasurementFormatter = {
let formatter = MeasurementFormatter()
formatter.unitStyle = .long
formatter.unitOptions = .providedUnit
return formatter
}()
var body: some View {
let calories = Measurement<UnitEnergy>(
value: nutritionFactKilocalories,
unit: .kilocalories
)
return VStack(alignment: .leading) {
Text(Self.measurementFormatter.string(from: calories))
Text("Energy: \(calories, formatter: Self.measurementFormatter)")
}
}
}
Key points:
Measurement<UnitEnergy>Represents an energy value with units. -MeasurementFormatterSet the unit style to.long。.providedUnitKeep the incoming.kilocaloriesunit.- first
TextFirst convert the measurement value into a string. - the second
TextUse formatter in interpolation.
(06:22) iOS 15’s new formatting API can declare formats on placements.
import Foundation
import SwiftUI
struct CaloriesView: View {
let nutritionFactKilocalories: Double
var body: some View {
let calories = Measurement<UnitEnergy>(
value: nutritionFactKilocalories,
unit: .kilocalories
)
return VStack(alignment: .leading) {
Text(calories.formatted(.measurement(width: .wide, usage: .food)))
Text("Energy: \(calories, format: .measurement(width: .wide, usage: .food))")
}
}
}
Key points:
calories.formatted(...)Directly returns the display text suitable for the current locale. -.measurement(width: .wide, usage: .food)Declare the display width and usage scenarios of measured values. -usage: .foodTell the system this is a food energy scenario. -TextThe interpolation can be directly receivedformat:, the code is closer to UI semantics.
Keyboard shortcuts will be remapped according to the current keyboard layout
(06:53) macOS Monterey and iPadOS 15 will adjust shortcut keys defined in SwiftUI based on the user’s current keyboard layout.
Apple’s example isCommand +. On a US keyboard it’s easy to type; on a Lithuanian keyboard the original combination cannot be typed while holding down Command. The system will remap it into a combination that can be entered.
import SwiftUI
struct SmoothieCommands: Commands {
let smoothie: Smoothie
var body: some Commands {
CommandMenu(Text("Smoothie", comment: "Menu title for smoothie-related actions")) {
SmoothieFavoriteButton(smoothie)
.keyboardShortcut("+")
}
}
}
struct Smoothie {}
struct SmoothieFavoriteButton: View {
let smoothie: Smoothie
init(_ smoothie: Smoothie) {
self.smoothie = smoothie
}
var body: some View {
Button("Favorite") {}
}
}
Key points:
CommandMenuThe title usesText, you can add translation comments. -SmoothieFavoriteButton(smoothie)It is the action entry in the menu. -.keyboardShortcut("+")Define the shortcut key for adding favorites.- The system adjusts the input combinations according to the current keyboard layout, and developers do not need to write branches for each keyboard layout.
Xcode 13’s localization workflow is more compiler dependent
(08:47) Xcode 13 enhances Swift string extraction. Build Setting in the projectUse Compiler to Extract Swift StringsIt is enabled by default for new Swift projects, and can be opened manually for old SwiftUI projects.
import SwiftUI
struct StepperView: View {
var label: LocalizedStringKey
@Binding var value: Int
var body: some View {
Stepper(value: $value) {
Text(label)
}
}
}
Key points:
labeluseLocalizedStringKey, to prevent custom views from swallowing localized information. -@Binding var valueReceive external status. -Stepper(value: $value)Modify the binding value. -Text(label)Display localizable labels next to steppers.
(13:53) The Xcode localization catalog will display key, source string, translation and comment. The translator cannot see variable names, so ambiguous strings must be commented.
import SwiftUI
struct FavoritesTab: View {
var body: some View {
Label {
Text("Favorites", comment: "Tab title. Noun: the list of favorite smoothies.")
} icon: {
Image(systemName: "heart")
}
}
}
Key points:
LabelUsed for tab bar items.- for title
TextInitialization is required to providecomment. - Notes
Favoritesis a noun that refers to a collection list. - Translators don’t have to guess whether it’s an action or a column name.
Core Takeaways
-
What to do: Perform a localization type audit on the custom component. Why it’s worth doing: This session makes it clear that custom SwiftUI views should use
LocalizedStringKeyor receiveText, otherwise the string may not be exported correctly. How to start: Search in the projectvar title: String、let label: String, first change the display parameters toLocalizedStringKey, and then use pseudo-language preview to check. -
What to do: Supplement translation annotations for high-risk copywriting such as payment, collection, and subscription. Why it’s worth doing: The variable name cannot be seen in the translation in the Xcode catalog.
Buy recipe for %@Such strings can be ambiguous. How to start: PutText("Favorites")Change toText("Favorites", comment: "...");LabelNeed to useLabel { Text(...) } icon: { ... }Writing method. -
What: Migrate numerical display from handwritten strings to
FormatStyle. Why it’s worth doing: Calories, length, weight, date have different formats in different regions,Text("%lf Calories")Regional differences will be thrown to the translation. How to start: PutMeasurementFormatterOr string concatenation is replaced byvalue.formatted(...),existTextused in interpolationformat:。 -
What to do: Use Markdown to manage emphasis styles in localized text. Why it’s worth doing: Different languages may emphasize different positions. Embed the style in a translatable string, and the translation can adjust the key words. How to start: Put multiple
TextSpliced emphasis copy is combined into a Markdown string, e.g.Text("A *real kick*!")。 -
WHAT: Add pseudo-language and keyboard layout checks before publishing. Why it’s worth doing: Pseudo-language can expose unextracted strings, and non-US keyboards can expose uninputable shortcut keys. How to start: Select Accented Pseudolanguage in the App Language of the scheme editor; reserved for common commands
.keyboardShortcut(...), letting macOS and iPadOS do layout remapping.
Related Sessions
- Streamline your localized strings — Continue to talk about the organization, plural form, formatting and Xcode export process of localized strings.
- What’s new in Foundation — Introducing Swift native
AttributedString, Markdown, and the new formatting API. - What’s new in SwiftUI — Overview of text, formatting, keyboard interaction, and multi-platform updates in SwiftUI 2021.
- Support Full Keyboard Access in your iOS app — Explain how to make the app better support keyboard navigation and auxiliary input.
Comments
GitHub Issues · utterances