Build global apps: Localization by example
Description: Learn how you can run your apps on devices around the world and help everyone have a great experience — regardless of the language they speak. We'll explore how Apple APIs can provide a solid foundation when creating apps for diverse audiences, and we'll share examples, challenges, and best practices from our own experiences.
Translation
- Use
String(localized:comment:)
for localizing text
let windPerceptionLabelText = String(
localized: "Wind is making it feel cooler",
comment: "Explains the wind is lowering the apparent temperature"
)
- new
String(localized:defaultValue:comment)
for the same English word but different translations - Don’t assume that prepositions will be the same in other languages for interchangeable dynamic data, such as a city name & location description
comment
is really important for translators, give them the context- What interface element
- What context
- What each variable is
- When Server sends a list of supported languages, use
Bundle.preferredLocalizations(from: allServerLanguages).first
on phone to get the most fitting language - for pluralized texts, use a Stringsdict file or automated grammar agreement
String(localized: "\(amountOfRain) in last ^[\(numberOfHours) hour](inflect: true).",
comment: "Label showing how much rain has fallen in the last number of hours")
Formatters
- for unit numbers use
.formatted
on the number, e.g. with the.percent
type - Formatters available for almost everything (session “Formatters make data human friendly” from past years)
- Combine formatters with text
- use
UnitLength(forLocale: .current, usage: .rainfall)
for the preferred unit - use
Measurement
type for unit-ful values
- use
func expectedPrecipitationIn24Hours(for valueInMillimeters: Measurement<UnitLength>) -> String {
// Use user's preferred measures
let preferredUnit = UnitLength(forLocale: .current, usage: .rainfall)
let valueInPreferredSystem = valueInMillimeters.converted(to: preferredUnit)
// Format the amount of rainfall
let formattedValue = valueInPreferredSystem
.formatted(.measurement(width: .narrow, usage: .asProvided))
let integerValue = Int(valueInPreferredSystem.value.rounded())
// Load and use formatting string
return String(localized: "EXPECTED_RAINFALL",
defaultValue: "\(integerValue) \(formattedValue) expected in next \(24)h.",
comment: "Label - How much precipitation (2nd formatted value, in mm or Inches) is expected in the next 24 hours (3rd, always 24).")
}
Stringsdict
entry starts with a key- provide for
other
first - provide any others needed per language
- provide for
Swift Packages
- provide
defaultLocalization
in package definition - you can now export localizations from packages, too: Go to Products > Export Localizations and choose your package
- will export as
.xcloc
files for translators, can be imported again String(localized:bundle:comment:)
used in packages- pass
.module
for bundle in packages
- pass
- Localize your package, advertise supported languages
- Developers should ensure dependencies are localized & test
- Layout and SwiftUI
- don’t give UI elements a fixed height, some languages like Hindi need more line height for the same text
- Adjust a column width in a table like list to the longest label
- use
Grid
view in SwiftUI to implement this
- use two or more lines if needed, e.g. for German on watchOS
- Sometimes a horizontal stack can be changed to a vertical to fit
- Possible with
ViewThatFits
in SwiftUI now