18

I am trying to localize my SwiftUI Watch app. I don't have any problems with static strings. I use LocalizedKeyStrings in my Text views and add my translations in Localizable.strings files. For example:

Text("history")

in Localizable.strings:

"history" = "Historique";

Result : "Historique"

But I also want to localize stings using interpolation. For example:

Text("startCustom \(format: "%.1f",customDistance)")

In Localizable.strings, I have tried with different syntax:

"startCustom %@" = "Course de %@ km";

or

"startCustom %f" = "Course de %f km";

or

"startCustom %.1f" = "Course de %.1f km";

Nothing works. I don't find any documentation for that ...

3 Answers3

33

Apparently, a LocalizedStringKey will automatically generate the localization key depending on the type of the values interpolated. For example, if you have the following Texts

Text("title key")
Text("name key \("Club")")
Text("count key \(8)")
Text("price key \(6.25)")

Your Localizable.strings file should look like

"title key" = "Sandwiches";
"name key %@" = "Name: %@";
"count key %lld" = "%lld sandwiches";

// You can change the format specifier in the value, but not in the key.
"price key %lf" = "Price: %.2lf";  

Be careful if you want to support 32-bit systems (iPhone 5 or earlier). In a 32-bit system, Int is Int32, the key of "int32 key \(Int32(8))" is "int32 key %d". You can always convert an integer to Int64 like in "count key \(Int64(8))" to enforce consistent keys across different systems.

Remark 1: For people who want to know how it works. When you use a string literal or an interpolated string such as "count key \(8)" in Text, the compiler will consider the string as a LocalizedStringKey, because Text has an initializer

init(_ key: LocalizedStringKey, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil),

and LocalizedStringKey conforms to ExpressibleByStringLiteral and ExpressibleByStringInterpolation and thus can be implicitly initialized from a string literal or a string interpolation.

Remark 2: If you're not sure what the key is, you can get the answer yourself by po a LocalizedStringKey in the debugger like this:

po LocalizedStringKey("count key \(8)")
Cosyn
  • 4,404
  • 1
  • 33
  • 26
  • 3
    Excellent answer. In case anyone else is having problems, I finally discovered with Xcode 12.0.1 that the SwiftUI iOS 14 previews DO NOT work with localizations of strings with variables, e.g. Text("count key \(x)") but the same localizations DO work correctly when run on the simulator or device. So don't trust the previews. – arcdale Oct 16 '20 at 12:18
  • @arcdale I found preview sometimes works sometimes doesn't, maybe a bug. – Cosyn Oct 17 '20 at 10:14
  • 1
    Your advice to use the debugger to find the correct format is genius! Solved my issue. – aeskreis Dec 12 '20 at 03:45
  • 1
    Other string format specifiers: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html – user482594 Aug 17 '21 at 08:36
  • Had to use %lld for integer tho. Took some time till figured it out – Dorian Pavetić Dec 28 '22 at 13:20
15

The following simple just works (tested with Xcode 11.4)

Text(String(format: NSLocalizedString("startCustom %.1f", comment: ""), 
     self.customDistance))

with Localizable.string having

"startCustom %.1f" = "Course de %.1f km";
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • It's almost perfect, thanks, but I still have a bug: it displays the text in English instead French when I use the "fr" localization. All the other translations are right, but this one seems to only use the English Localizable.strings – Raphaël Barthomeuf May 27 '20 at 12:46
  • You can forget my last comment. It's a bug only with Xcode and/or simulator. It works well on the real device. Thanks for you easy and helpful solution !! – Raphaël Barthomeuf May 27 '20 at 13:03
  • when using this approach, after applying translation app renders the text in this format: "Course de ("15.5") km" any ideas why? – eja08 Jun 14 '20 at 18:33
5

My way

Localizable file

"myNameIs %@" = "My name is %@.";

SwiftUI file

struct TestLocalize: View {
        
    var name = "Hien Nguyen"
    
    var body: some View {
        Text("myNameIs \(name)")
    }
}

Result

My name is Hien Nguyen

Hien.Nguyen
  • 282
  • 5
  • 3