How to change LocalizedStringKey to String in SwiftUI

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?

Share

Improve this question

Follow

asked Mar 25, 2020 at 1:45

jonye._.jin

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. 

    – jonye._.jin

     Mar 25, 2020 at 5:25

Add a comment

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`

Share

Improve this answer

Follow

edited Aug 25 at 21:03

answered Sep 18, 2020 at 8:01

Mahdi BM

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). 

    – Devin McKaskle

     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 

    – Andrew___Pls_Support_UA

     Aug 25 at 8:23
  • 1

    @Andrew____Pls_Support_Ukraine fixed. only needed adding as? String

    – Mahdi BM

     Aug 25 at 21:04

Add a comment

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.

Share

Improve this answer

Follow

edited May 10 at 2:34

shim

8,5991010 gold badges7272 silver badges103103 bronze badges

answered Apr 16 at 19:15

Rafael Bitencourt

11111 silver badge55 bronze badges

  • 1

    It works for iOS15+. Is there any native approach for iOS 14? 

    – test1229

     Sep 8 at 13:01

Add a comment

4

You can use NSLocalizedString.

let localizedString = NSLocalizedString("LOCALIZED-STRING-KEY", comment: "Describe what is being localized here")

Share

Improve this answer

Follow

answered Jul 20, 2020 at 22:59

emjeexyz

33433 silver badges66 bronze badges

  • 4

    not relevant to SwiftUI. LocalizedStringKey is a type. 

    – Tiziano Coroneo

     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 

    – sumofighter666

     May 1 at 8:38

Add a comment

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
    }
}

Share

Improve this answer

Follow

answered Sep 9 at 13:06

Learn OpenGL ES

4,66511 gold badge3434 silver badges3838 bronze badges

Add a comment

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()

Share

Improve this answer

Follow

edited 19 hours ago

answered 22 hours ago

Andrew___Pls_Support_UA

8,24255 gold badges5252 silver badges8787 bronze badges

Add a comment

-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()

Share

Improve this answer

Follow

edited Jul 21, 2020 at 1:58

answered Jul 21, 2020 at 1:03

Tema Tian

19511 silver badge1212 bronze badges

  • 1

    not relevant to SwiftUI. LocalizedStringKey is a type. 

    – Tiziano Coroneo

     Jul 28, 2020 at 13:35

Add a comment

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值