How to use NSLocalizedString function with variables in Swift?
Asked Answered
S

8

105

I'm trying to localize my app using NSLocalizedString. When I import the XLIFF file, most works like a charm but something do not and some string is not localized. I have noticed that the problem is from NSLocalizedString containing something variable inside like:

NSLocalizedString(" - \(count) Notifica", comment: "sottotitolo prescrizione per le notifiche al singolare")

or

NSLocalizedString("Notifica per \(medicina!) della prescrizione \(prescription!)\nMemo: \(memoTextView.text)", comment: "Messaggio della Local Notification")

Maybe this is not the correct syntax for this kind of stuff. Someone can explain me how to do that in Swift?

Sweetener answered 9/10, 2014 at 11:45 Comment(1)
This is a very good article about localization in Swift for a robust architectureLucianolucias
P
166

You can use the sprintf format parameters within NSLocalizedString, so your example can look like this:

let myString = String(format: NSLocalizedString(" - %d Notifica", comment: "sottotitolo prescrizione per le notifiche al singolare"), count)
Piperpiperaceous answered 9/10, 2014 at 12:0 Comment(6)
How does it look like in the Localizable.stringGoodsell
same as in Obj-C: " - %d Notifica"=" - %d Notifica";Thermopile
How do i substitute a string? I tried to use %s modifier which didn't work =\Medicinal
@Medicinal Use %@ for substituting a string.Twit
The reference for these formatting parameters is developer.apple.com/library/content/documentation/Cocoa/…Dasya
Can you tell me the use of comment parameters inside NSLocalizedString() ??Orella
W
114

In Session #412 of the WWDC2014 "Localizing with Xcode 6" the proper way to this in Swift is the following:

String.localizedStringWithFormat(
    NSLocalizedString(" - %d Notifica",
    comment: "sottotitolo prescrizione per le notifiche al singolare"),
    count)

Note that localizedStringWithFormat sets the returned String's local based on given first argument:

  • No, it does not translate anything.
  • This confusion comes from wrong naming of NSLocalizedString.
  • It should have been named NSTranslatedString, or NSTranslatable (instead of NSLocalizedString).
Wyeth answered 28/6, 2015 at 21:29 Comment(3)
Why do you need to use NSLocalizedString(...)? doesn't it happen in the implementation of String.localizedStringWithFormat(...)?Yard
Check out (#26238049)Wyeth
Thanks I already saw it after I asked. It will be very helpful for others so thanksYard
S
26

I have followed the approach of creating extension to String as i have many strings to localize.

extension String {
    var localized: String {
        return NSLocalizedString(self, comment:"")
    }
}

To use it for localization in code do:

self.descriptionView.text = "Description".localized

For strings with dynamic variables follow :

self.entryTimeLabel.text = "\("Doors-open-at".localized) \(event.eventStartTime)"

Declare the strings in String files for different languages (example : Arabic and English)

enter image description here enter image description here

Hope will be helping!

Selfabasement answered 28/6, 2017 at 6:57 Comment(7)
But it seems to me you're just attaching the time to the string. What if your localised string was like The doors open at %@ o'clock. Would your solution still work?Kneedeep
Yes, it is working perfectly as i'm getting time as String from back.Selfabasement
Thanks for including a reference to Localizable.strings. However, I think @Kneedeep has a valid concern.Trelliswork
I don't know why people want to drop out "comment" value. It gives the description of the text and its purpose to localisation engineers without which they cannot make out the intention to use that text on a button or as a label etc.Bundesrat
This is not ok as Houman said, but it's a generic way of concatenate strings.Stcyr
This is not a good idea, because it assumes that the "doors open at" text will precede the time value in every language, but this is not necessarily true. It's better to use localizedStringWithFormat so that you can vary the position of the interpolated value if needed.Detraction
this answer is totally incorrect! In some languages you may have a different substring order to insert bad you hardcode the orderSherleysherline
E
17

Here is an extension I use in String, it adds a localizeWithFormat function with variable arguments,

extension String {

     func localizeWithFormat(arguments: CVarArg...) -> String{
        return String(format: self.localized, arguments: arguments)        
     }
            
     var localized: String{
         return Bundle.main.localizedString(forKey: self, value: nil, table: "StandardLocalizations")
     }
}

Usage:

let siriCalendarText = "AnyCalendar"
let localizedText = "LTo use Siri with my app, please set %@ as the default list on your device reminders settings".localizeWithFormat(arguments: siriCalendarTitle)

Just be careful not to use the same function and property names that String has. I normally use a 3 letter prefix for all my framework functions.

Exuviate answered 12/10, 2018 at 19:28 Comment(0)
C
16

I tried the above solutions however the code below worked for me

SWIFT 4

extension String {

    /// Fetches a localized String
    ///
    /// - Returns: return value(String) for key
    public func localized() -> String {
        let path = Bundle.main.path(forResource: "en", ofType: "lproj")
        let bundle = Bundle(path: path!)
        return (bundle?.localizedString(forKey: self, value: nil, table: nil))!
    }


    /// Fetches a localised String Arguments
    ///
    /// - Parameter arguments: parameters to be added in a string
    /// - Returns: localized string
    public func localized(with arguments: [CVarArg]) -> String {
        return String(format: self.localized(), locale: nil, arguments: arguments)
    }

}

// variable in a class
 let tcAndPPMessage = "By_signing_up_or_logging_in,_you_agree_to_our"
                                     .localized(with: [tAndc, pp, signin])

// Localization File String
"By_signing_up_or_logging_in,_you_agree_to_our" = "By signing up or logging in, you agree to our \"%@\" and \"%@\" \nAlready have an Account? \"%@\"";
Cancellation answered 4/6, 2019 at 14:23 Comment(0)
D
2

I wrote the same functions for UILabel

extension UILabel {
    
    func setLocalizedText(key: String) {
        self.text = key.localized
    }
    
    func setLocalizedText(key: String, arguments: [CVarArg]) {
        self.text = String(format: key.localized, arguments: arguments)
    }
}

If you want you can move this localized property to UILabel as well

extension String {
        
    var localized: String{
        return Bundle.main.localizedString(forKey: self, value: nil, table: nil)
    }
}

My localizable

"hi_n" = "Hi, %@!";

Used them like this:

self.greetingLabel.setLocalizedText(key: "hi_n", arguments: [self.viewModel.account!.firstName])
// Shows this on the screen -> Hi, StackOverflow!
Dormer answered 27/2, 2021 at 10:21 Comment(2)
How does swift know which "setLocalizedText" to pick since in your string extension, there are 2?Groundspeed
@RobertBrax it will know by the number of arguments you are passing.Dormer
E
0

I suggest writing a custom global function instead of an extension, because genstrings is just parsing the source code for NSLocalizedString with literals. That means you wont be able to automatically generate the .strings files from your source coder with the extension solutions.

func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String, with arguments: CVarArg...) -> String {
    let localizedString = Foundation.NSLocalizedString(key, tableName: tableName, bundle: bundle, value: value, comment: comment)
    return String.localizedStringWithFormat(localizedString, arguments)
}
Eddi answered 18/8, 2023 at 20:52 Comment(0)
D
-5

I created an extension to String since I had many strings to be localized.

extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
}

For example:

let myValue = 10
let anotherValue = "another value"

let localizedStr = "This string is localized: \(myValue) \(anotherValue)".localized
print(localizedStr)
Decemvirate answered 20/12, 2016 at 16:50 Comment(4)
The big downside to this approach is that you have to manually extract the strings to send to the translator as Editor > Export for Localization... won't pick them up.Provost
Given what @JasonMoore suggested, I don't think this is the right approach.Saval
@JasonMoore totally agree with you. Did any of you guys find a solution for this?Repeal
i don't knew why this solution is downrated :( . and almost the below nest below solution is the same but it have uprateHamish

© 2022 - 2024 — McMap. All rights reserved.