-
Notifications
You must be signed in to change notification settings - Fork 5
Spec: Text ‐ Localization
SwiftUI is not the only UI framework developed by Apple to build natively on Apple platforms. UIKit and AppKit are older frameworks, but still widely used. They can even be integrated inside SwiftUI. Some localization constructs are shared between these frameworks and since SwftUI is the youngest of the family, there are some limitations or awkward edge cases when using some of them. They will be noted where relevant.
Supporting multiple languages in your app is a good overview of the tools available for localization. Look at Xcode's localization documentation for more information and examples.
If you initialize a text view with a string literal, the view uses the init(_:tableName:bundle:comment:)
initializer, which interprets the string as a localization key and looks up its localization value for the app's locale in the given table. If the locale is not supported, the table is not found or there is no value for the key, its value is displayed in the UI as is.
Text("pencil") // displays "pencil" if no localization is found
If you intialize a text view with a variable value, the view uses the init(_:)
initializer, which doesn’t localize the string. However, you can request localization by creating a LocalizedStringKey
instance first, which triggers the init(_:tableName:bundle:comment:)
initializer instead:
let writingImplement = "pencil"
Text(writingImplement) // displays "pencil" for all locales
Text(LocalizedStringKey(writingImplement)) // uses localization
To explicitly bypass localization for a string literal, use the init(verbatim:)
initializer.
Text(verbatim: "pencil") // displays "pencil" for all locales
LocalizedStringResource
can be used to specify the Text initializer parameters outside of UI code, for example:
struct SomeController {
static var title = LocalizedStringResource(
"pencil",
table: "MyTable",
comment: "my comment",
)
}
// these display the same thing
Text(SomeController.title)
Text("pencil", table: "MyTable", comment: "my comment")
Note: One of the uses for a LocalizedStringResource
is "to provide localizable strings with lookups you defer to a later time". In Swift this refers to the passing of localizable strings to other processes, which may have different locales from the process where they originated from. It's unclear if this capability can be useful in the context of the swift_ui package.
String
, in the context of localization, has initializers of the form init(localized:...)
that take similar parameters to the String literal initializer. For example: init(localized:defaultValue:options:table:bundle:locale:comment:)
.
The new parameters are:
-
defaultValue
: can be used to specify the localized value for the default locale. Useful when the value oflocalized
isn't intended to be displayed. -
options
: used to specify formatting options. -
locale
: can be used to explicitly specify a locale.
Text(LocalizedStringKey(String(localized: "pencil")))
Note: we need to use LocalizedStringKey
because String
is not a string literal (see variable section).
AttributedString
can be used to associate style and attributes to runs of text. Like String
, it has various initializers of the type init(localized:options:table:bundle:locale:comment:)
, with the parameters playing the same roles.
let attributed = AttributedString(localized: "pencil")
Text(attributed)
Note: With AttributedString
the localized value can only be displayed in the language currently set in the system and cannot be specified as a specific language, even setting the locale
attribute does not work. This is one of the incompatibilities I was referring to before.
String
and AttributedString
are awkward to work with in swiftUI (localization-wise, at least), and don't seem to be completely supported. A more through investigation is needed to discover their limits in swiftUI, but this goes outside of the Text
specification. Besides, all the features offered by them can be achieved with the Text
view and string literals directly, albeit with a different API.
This needs to be investigated further.
In the initializers mentioned untile now there is the table parameter. This refers to the name of the file that contains the localization values for the Text's string. There are various file formats available to create these tables: Strings
and Stringsdict
files (legacy), and String catalog
s.
The latter are the recommended format for new projects in Xcode 15 (example here). They can be auto-generated for swiftUI code from Xcode using the build setting SWIFT_EMIT_LOC_STRINGS = YES
.
A String catalog is a json file with the .xcstrings
extension, and the usually only one is needed (named Localizable
). If more are needed (for a better organization or to split a large one) the convention is to name them LocalizableXXX
(eg. LocalizableFoo, LocalizableBar), but any name is acceptable. For example, you could have one catalog per feature: LocalizableSettings
, LocalizableAuthentication
, LocalizableHome
ecc. The same file contains the localization for its keys in all the supported locales.
Xcode renders them with an interactive UI:

Another parameter of the initializers is bundle
. It is used to lookup localizations in a bundle that is external the application. This functionality is not useful for the swift_ui
package.
For some supported languages, swiftUI can automatically choose the correct gender, plural form or pronoun for a sentence, without the need to specify anything in the string catalogs.
In the example, note that the displayed string has been adapted ("grandi" instead of "grande", "insalate" instead of "insalata"), just by adding the inflect: true
attribute.
let quantity = 2
let size = LocalizedStringResource("large") // grande in italian
let food = LocalizedStringResource("salad") // insalata in italian
Text("Add ^[\(quantity) \(size) \(food)](inflect: true) to your order")
// Displays "Aggiungi 2 grandi insalate al tuo ordine" in italian
See the WWDC video for more info.
Note: There are other mechanisms like this (Term of address, Inflection rule, Morphology, Inflection concept), that affect all localizable strings, even outside the Text
view, that need their own specification. It's unclear how we can achieve something similar in the swift_ui
package.