97

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?

Paulo Mattos
  • 17,605
  • 10
  • 69
  • 79
msalafia
  • 2,543
  • 4
  • 19
  • 31
  • This is a [very good article](https://medium.com/@mendibarouk/enhance-your-localized-capabilities-on-your-ios-applications-d3ba17138077) about localization in Swift for a robust architecture – Mendy Apr 07 '19 at 08:09

7 Answers7

158

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)
zisoft
  • 22,218
  • 10
  • 59
  • 73
106

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)
Mark
  • 14,724
  • 18
  • 73
  • 98
  • 3
    Why do you need to use NSLocalizedString(...)? doesn't it happen in the implementation of String.localizedStringWithFormat(...)? – Yitzchak Sep 27 '16 at 05:27
  • 3
    Check out (http://stackoverflow.com/questions/26237549/how-does-localizedstringwithformat-work) – Mark Sep 27 '16 at 12:40
  • 2
    Thanks I already saw it after I asked. It will be very helpful for others so thanks – Yitzchak Sep 27 '16 at 12:56
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!

JaspreetKour
  • 681
  • 8
  • 9
  • 4
    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? – Houman Jun 04 '18 at 19:56
  • Yes, it is working perfectly as i'm getting time as String from back. – JaspreetKour Jun 05 '18 at 13:40
  • 2
    Thanks for including a reference to `Localizable.strings`. However, I think @Houman has a valid concern. – Matt Nov 14 '18 at 19:35
  • 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. – Satyam Jul 19 '20 at 07:11
  • This is not ok as Houman said, but it's a generic way of concatenate strings. – trusk Jun 02 '21 at 11:43
15

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? \"%@\"";
Pratik
  • 556
  • 8
  • 9
12

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.

Ahmadreza
  • 6,284
  • 2
  • 41
  • 62
the Reverend
  • 11,602
  • 9
  • 62
  • 111
1

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!
OhhhThatVarun
  • 3,431
  • 2
  • 21
  • 43
-4

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)
Santosh
  • 2,874
  • 1
  • 15
  • 16
  • 6
    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. – Jason Moore Jan 23 '17 at 17:29
  • Given what @JasonMoore suggested, I don't think this is the right approach. – Yuchen Feb 13 '17 at 20:20
  • @JasonMoore totally agree with you. Did any of you guys find a solution for this? – gasparuff Apr 12 '17 at 19:39
  • i don't knew why this solution is downrated :( . and almost the below nest below solution is the same but it have uprate – Amr Angry Aug 21 '17 at 14:35