Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change LocalizedStringKey to String in SwiftUI

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?

like image 896
jonye._.jin Avatar asked Mar 25 '20 01:03

jonye._.jin


3 Answers

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 https://stackoverflow.com/a/27879342/11837341

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`
like image 98
Mahdi BM Avatar answered Oct 18 '22 22:10

Mahdi BM


You can use NSLocalizedString.

let localizedString = NSLocalizedString("LOCALIZED-STRING-KEY", comment: "Describe what is being localized here")
like image 40
mattigrthr Avatar answered Oct 18 '22 23:10

mattigrthr


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.

like image 4
Rafael Bitencourt Avatar answered Oct 18 '22 22:10

Rafael Bitencourt