ios - How to change LocalizedStringKey to String in SwiftUI - Stack Overflow
Asked 2 years, 8 months ago
Modified today
Viewed 13k times
25
I am trying to localize markers shown in my AppleMapView using SwiftUI.
However, MKAnnotation's marker title's type is fixed to String
. And I don't want to inherit or create custom class because it is too bothering.
What I need is just cast LocalizedStringKey to String to set marker's title. Any help on this?
Follow
asked Mar 25, 2020 at 1:45
48111 gold badge44 silver badges1616 bronze badges
-
3
I would do this in opposite order, store/use everywhere String (because it is model) and only in needed places created LocalizedStringKey(String) (because it is UI-only).– Asperi
Mar 25, 2020 at 4:28 - @Asperi I don't get it. MKAnnotation().title 's type is String and that's the problem. Mar 25, 2020 at 5:25
6 Answers
Sorted by:
Highest score (default) Trending (recent votes count more) Date modified (newest first) Date created (oldest first)
27
EDIT: This answer has been edited once for cleaner code and a bit better performance in stringKey
.
LocalizedStringKey
has a member called key
which contains the key string which corresponds to the localized string that is in the localization files. We can't access the key directly unfortunately, so we need to workaround getting the key.
// An Example that won't work:
let localizedKey = LocalizedStringKey.init("SOME_LOCALIZED_KEY_HERE")
localizedKey.key // ERRROOOOORR! `key` is an internal member of `LocalizedStringKey` and you can't access it!
workaround extension, plus an example of how it works, to get the key out of the LocalizedStringKey:
extension LocalizedStringKey {
// This will mirror the `LocalizedStringKey` so it can access its
// internal `key` property. Mirroring is rather expensive, but it
// should be fine performance-wise, unless you are
// using it too much or doing something out of the norm.
var stringKey: String? {
Mirror(reflecting: self).children.first(where: { $0.label == "key" })?.value as? String
}
}
// An Example:
let localizedKey = LocalizedStringKey("KEY_HERE")
print(localizedKey.stringkey)
// prints `KEY_HERE`
now that we have the key as an string, you can easily get the localized string which is pointed to by the key of LocalizedStringKey.
extension String {
static func localizedString(for key: String,
locale: Locale = .current) -> String {
let language = locale.languageCode
let path = Bundle.main.path(forResource: language, ofType: "lproj")!
let bundle = Bundle(path: path)!
let localizedString = NSLocalizedString(key, bundle: bundle, comment: "")
return localizedString
}
}
to understand this, take a look at ios - Force NSLocalizedString to use a specific language using Swift - Stack Overflow
now you can easily convert a LocalizedStringKey's value to string:
extension LocalizedStringKey {
func stringValue(locale: Locale = .current) -> String {
return .localizedString(for: self.stringKey, locale: locale)
}
}
TL; DR (Summary)
add these extensions to your project:
extension LocalizedStringKey {
var stringKey: String? {
Mirror(reflecting: self).children.first(where: { $0.label == "key" })?.value as? String
}
}
extension String {
static func localizedString(for key: String,
locale: Locale = .current) -> String {
let language = locale.languageCode
let path = Bundle.main.path(forResource: language, ofType: "lproj")!
let bundle = Bundle(path: path)!
let localizedString = NSLocalizedString(key, bundle: bundle, comment: "")
return localizedString
}
}
extension LocalizedStringKey {
func stringValue(locale: Locale = .current) -> String {
return .localizedString(for: self.stringKey, locale: locale)
}
}
Examples
let localizedKey = LocalizedStringKey("KEY_NAME_HERE")
print(localizedKey.stringKey)
//prints `KEY_NAME_HERE`
print(localizedKey.stringValue())
// prints Localized value of `KEY_NAME_HERE`
// DOESNT print `KEY_NAME_HERE`
Follow
answered Sep 18, 2020 at 8:01
1,51899 silver badges1515 bronze badges
- This might go without saying but since this is relying on undocumented, internal representations of
LocalizedStringKey
this is brittle.components[1][0]
could cause crashes if the output of description ever changes (which could happen with any new version of SwiftUI). May 21 at 17:48 - Yes you are correct. In production you should be safe and use guard, if let etc... at the time of writing this answer i wasn't too much worried about that, but now that i see more people are upvoting this answer, i might as well edit so it doesn't possibly make problems for people in a future version of SwiftUI
– Mahdi BM
May 22 at 9:14 - For everyone who will stumble upon this answer, please have a look at the native solution from @rafael-bitencourt. It is as simple as
String(localized: "YOUR_LOCALIZED_KEY")
– herve
May 25 at 12:55 - "Type of expression is ambiguous without more context" on the reflecting string Aug 25 at 8:23
-
1
@Andrew____Pls_Support_Ukraine fixed. only needed addingas? String
.– Mahdi BM
Aug 25 at 21:04
7
You can do it simply by using: String(localized: "YOUR_LOCALIZED_KEY")
Mahdi BM's solution has a problem, because Swift returns only the language code even if you are using variants of a language like Spanish and Portuguese and so many others. The language code for both examples will always return ES and PT, but the names of folders with the localized keys will be different: PT can be 'pt-PT' or 'pt-BR', Spanish can be 'es' or 'es-419' (Latin America) and these cases will cause your app to crash.
Follow
8,5991010 gold badges7272 silver badges103103 bronze badges
answered Apr 16 at 19:15
11111 silver badge55 bronze badges
-
1
It works for iOS15+. Is there any native approach for iOS 14?– test1229
Sep 8 at 13:01
4
You can use NSLocalizedString.
let localizedString = NSLocalizedString("LOCALIZED-STRING-KEY", comment: "Describe what is being localized here")
Follow
answered Jul 20, 2020 at 22:59
33433 silver badges66 bronze badges
-
4
not relevant to SwiftUI. LocalizedStringKey is a type. Jul 28, 2020 at 13:35 -
6
I understood @jonye._.jin's problem as that he needs to provide a string but he wants to display the title in different languages/localize it. I know this isn't the cast originally asked for but it solves the problem. In the end there is the translation as a String.– emjeexyz
Jul 29, 2020 at 14:32 -
1
Not relevant. Read the question properly May 1 at 8:38
1
I modified the top answer to compile on Xcode14, remove forced unwraps and to return the key when a translation wasn't found:
extension LocalizedStringKey {
var stringKey: String? {
Mirror(reflecting: self).children.first(where: { $0.label == "key" })?.value as? String
}
func stringValue(locale: Locale = .current) -> String? {
guard let stringKey = self.stringKey else { return nil }
let language = locale.languageCode
guard let path = Bundle.main.path(forResource: language, ofType: "lproj") else { return stringKey }
guard let bundle = Bundle(path: path) else { return stringKey }
let localizedString = NSLocalizedString(stringKey, bundle: bundle, comment: "")
return localizedString
}
}
Follow
answered Sep 9 at 13:06
4,66511 gold badge3434 silver badges3838 bronze badges
0
import Foundation
import SwiftUI
@available(macOS 10.15, *)
public extension LocalizedStringKey {
private var keyStr: String {
return "\(self)".keyFromLocalizedStringKey
}
func localizedStr(locale: Locale = .current) -> String {
return String.localizedString(for: self.keyStr, locale: locale)
}
}
fileprivate extension String {
static func localizedString(for key: String, locale: Locale = .current) -> String {
let language = locale.languageCode
let path = Bundle.main.path(forResource: language, ofType: "lproj")!
let bundle = Bundle(path: path)!
let localizedString = NSLocalizedString(key, bundle: bundle, comment: "")
return localizedString
}
var keyFromLocalizedStringKey: String {
let comp2 = self.substring(from: 25).components(separatedBy:"\", hasFormatting")
if comp2.count == 2 {
return comp2.first!
}
return "failed to get stringKey"
}
}
usage:
let lsk = LocalizedStringKey("KEY_NAME_HERE")
let key = lsk.keyStr
let translatedToCurrLocale = lsk.localizedStr()
Follow
answered 22 hours ago
8,24255 gold badges5252 silver badges8787 bronze badges
-1
Add an extension to the string to read the localized language
extension String {
func localized() -> String {
let path = Bundle.main.path(forResource: "your language", ofType: "lproj")!
if let bundle = Bundle(path: path) {
let str = bundle.localizedString(forKey: self, value: nil, table: nil)
return str
}
return ""
}
}
Use LocalizedStringKey to load sample code
let title: String = "LocalizedStringKey".localized()
Follow
answered Jul 21, 2020 at 1:03
19511 silver badge1212 bronze badges
-
1
not relevant to SwiftUI. LocalizedStringKey is a type. Jul 28, 2020 at 13:35