How to implement localization in Swift UI
When you look at documentation for Text
you can see that it takes LocalizedStringKey
not a String
into its initializer:
init(_ key: LocalizedStringKey, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil)
It makes localizing very straightforward. All you have to do is:
- create a new file of type "Strings File", call it
Localizable.strings
- select the new file and navigate to File Inspector in the right hand side panel and click Localize...
- go to your project file to the Localizations section and add another language to the list - Xcode will create localization files for you
When you select you Localizable.strings
you will see that it contains files for the original language and the language you have just added. That's where you put your translations, i.e. key - localized text pairs.
If you have a text like this is your app:
Text("Hello World!")
You have to now add to your Localizable.strings
your translations:
for your base language:
"Hello World!" = "Hello World!";
and for your second language (in this case German):
"Hello World!" = "Hallo Welt!";
To see your previews localised you can define them like this:
struct ContentViewView_Previews: PreviewProvider {
static var previews: some View {
ForEach(["en", "de"], id: \.self) { id in
ContentView()
.environment(\.locale, .init(identifier: id))
}
}
}
SwiftUI localization doesn't work shows only keys Xcode
Make sure you have the Localizable.strings
file in your project. There is where LocalizedStringKey
looks for the keys/values as a default.
https://developer.apple.com/documentation/swiftui/localizedstringkey
If you want to define a different file use the
Text(LocalizedStringKey, tableName: String?, bundle: Bundle?, comment: StaticString?)
initializer and the tableName
should match your .strings
file name.
SwiftUI Localization - how to make the UI component and its function the base for localization
Turns out that it is quite easy. All I had to do is provide the optional argument value
in the NSLocalizedString.init
.
The NSLocalizedString
function has the following signature
/// - parameter key: An identifying value used to reference a localized string.
/// Don't use the empty string as a key. Values keyed by the empty string will
/// not be localized.
...
/// - parameter value: A user-visible string to return when the localized string
/// for `key` cannot be found in the table. If `value` is the empty string,
/// `key` would be returned instead.
NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String)
If the value
argument is not provided the translation entry after exporting for localization looks as follows:
File.swift
NSLocalizedString("Cancel", comment: "Cancel button")
en.xliff
<trans-unit id="Cancel" xml:space="preserve">
<source>Cancel</source>
<target>Cancel</target>
<note>Cancel button</note>
</trans-unit>
However, if the value
argument is provided, the resulting translation entry looks as follows:
File.swift
NSLocalizedString("Navigation.Button.Cancel", value: "Cancel", comment: "Cancel button")
en.xliff
<trans-unit id="Navigation.Button.Cancel" xml:space="preserve">
<source>Cancel</source>
<target>Cancel</target>
<note>Cancel button</note>
</trans-unit>
Localization SwiftUI
You can use LocalizedStringKey
:
In your app:
let greeting: LocalizedStringKey = "Greeting"
let text = Text(greeting)
In your English Localizable.strings
file:
"Greeting" = "Hello";
In your Spanish Localizable.strings
file:
"Greeting" = "Hola";
SwiftUI Localization and Enums
The answer is much simpler than writing extensions and doing complicated work. Instead of writing a static let, when a variable is present you write a static func. This all takes place in the LocalizationString.swift file's enum and looks like this:
static func testText(name: String) -> LocalizedStringKey { LocalizedStringKey("TEST_TEXT \(name)") }
To use this in your view:
Text(LocalizationStrings.testTest(name: varname))
If you need more variables, just add them into the function.
SwiftUI: Variable strings not exported for localization
Ok, so after tinkering with localization some more, I found an approach that works well.
The tutorial I linked to (https://www.ibabbleon.com/swiftui_localization_tutorial.html) does not talk about this, and makes things confusing with LocalizedStringKey and Text(String, comment: String). Some other tutorials also go down this route, but it makes code really ugly because it moves data into Text. So if you want to separate data from the view, you have to include Text (a UI element) in the view model. Alternatively, if you use LocalizedStringKey, you can't include comments for the translator.
Fortunately, there is a much simpler way!
struct ContentView: View {
let normalString = "This is not exported for localization. Good for previews!"
let localizedString = String(localized: "This is exported for localization.", comment: "You can add a comment for the translator, too!")
var body: some View {
VStack {
Text(normalString)
Text(localizedString)
}
}
}
SwiftUI Localization
What you are doing is you are giving back an already interpolated string with %@
to an interpolated string. So the string that you are generating looks like this: "schoolLocation %@ Some Name"
. You can do it this way:
struct Translation {
struct school{
static func location(name: String): LocalizedStringKey {
return "schoolLocation \(name)"
}
}
}
And then you can use your translation like this:
var location = "Some Name"
.navigationBarTitle(Translation.school.location(name: location))
NSLocalizedString and value with SwiftUI
I have finally found an answer right after posting my question:
// ContentView.swift
Text("3 Tomatoes")
/* or */
Text("\(tomatoes.count) Tomatoes")
/* replaced by */
Text(String(format: NSLocalizedString("%lld text-tomatoes", comment: ""), tomatoes.count))
// Localizable.strings (en)
"%lld text-tomatoes" = "%lld Tomatoes";
It's working like a charm!
Other example: Localization with String interpolation in SwiftUI
Related Topics
How Do Set a Width and Height of an Image in Swift
How Should a Swift + Objective-C Project Be Setup for Unit Testing
Google Analytics 3.08 iOS Idfa Class Missing, Won't Collect Idfa
How to Add a Character at a Particular Index in String in Swift
How to Write Application Logs to File and Get Them
How to Get the Current Application Icon in iOS
Customizing the Mkannotation Callout Bubble
How to Have a Uiscrollview Scroll and Have a Gesture Recognizer
Object-C/iOS :How to Use Asynchronous to Get a Data from Url
Swiftui in iOS14 Keyboard Avoidance Issues and Ignoressafearea Modifier Issues
Where to Highlight Uicollectionviewcell: Delegate or Cell
Accessing the Settings App from Your App in iOS 8
Always Stop in App Delegate After Enabling All Exceptions Break Point
Can Swift Closures Be Set to a Default Value When Used as a Parameter in a Function
Generating Custom Thumbnail from Alassetrepresentation
How to Distribute Swift Library Without Exposing the Source Code
Link Errors with Parse.Framework iOS
Share Image with Hashtag via Uiactivityviewcontroller (Twitter, Facebook, Instagram)