What’s the equivalent to String.localizedStringWithFormat(_:_:) for SwiftUI's LocalizedStringKey?
Asked Answered
S

1

23

What’s the equivalent to String.localizedStringWithFormat(_:_:) in SwiftUI?

I know LocalizedStringKey.init(:) can make use of string interpolation, but as I understand it this requires localizable string keys to be parameterized in the .strings/.stringsdict files.

This is different to how localized string keys are currently defined in the app I'm working on. Given these localizable strings in Localizable.strings:

"HELLO_WORLD" = "Hello, world!";
"HELLO_WORLD_PARAMETERIZED" = "Hello, %@!";

this works just fine in the Foundation/UIKit world:

NSLocalizedString("HELLO_WORLD", comment: "") // "Hello, world!"
String.localizedStringWithFormat(NSLocalizedString("HELLO_WORLD_PARAMETERIZED", comment: ""), "Bob") // "Hello, Bob!"

But I don’t see how to make it work in SwiftUI:

let helloWorld = LocalizedStringKey("HELLO_WORLD")
Text(helloWorld) // ✅ Displays "Hello, world!" 
Text("HELLO_WORLD") // ✅ Also displays "Hello, world!" 

LocalizedStringKey("HELLO_WORLD_PARAMETERIZED", "Bob") // ❌ This won't compile, because LocalizedStringKey has no format parameter like `String.localizedStringWithFormat(_:_:)` does.

let bob = "Bob"
LocalizedStringKey("Hello, \(bob)!") // 🤔 This *would* work if the key in Localizable.strings were "Hello, %@!" – but this doesn't reflect the reality of localized string keys are currently defined for this app.

Text(verbatim: String.localizedStringWithFormat(NSLocalizedString("HELLO_WORLD_PARAMETERIZED", comment: ""), "Bob")) // 🙈 This correctly displays "Hello, Bob!" in the Text view, but... well, it ain't pretty.

Do I have to change all my localizable string keys (as opposed to just their values) to be parameterized in order to be able to use them in SwiftUI views (without using the Text(verbatim:) workaround)?

Sorority answered 3/6, 2020 at 8:25 Comment(2)
You've already found everything's available, so nothing to add. If string not format then just use it as-is, it will be translated automatically, if you need format then only via NSLocalizedString. That's it.Politi
Have a look here: developer.apple.com/documentation/swiftui/…Portal
G
18

I faced this issue as well and thanks to some sources and links I think I got it working the expected way.

I was working on Xcode 12 Beta 6 when I succeeded, I can not confirm/infirm on other versions.

The translation key needs to reflect the interpolated string you'll use in SwiftUI in which every argument is replaced by the String Format specifier representing the type of the argument.

In your example, you want to insert one String as parameter. This corresponds to the %@ specifier.

Rewrite your Localizable.strings by:

"HELLO_WORLD" = "Hello, world!";
"HELLO_WORLD_PARAMETERIZED %@" = "Hello, %@!";

To use it inside a Text:

Text("HELLO_WORLD_PARAMETERIZED \(someStringVar)")

If you want to use a UInt parameter, use the %llu identifier, %lld for Int (see the String Format specifier link)

The same rules apply for .stringdict, name the key using the same pattern:

<dict>
    <key>%llu elements</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%#@VARIABLE@</string>
        <key>VARIABLE</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>llu</string>
            <key>zero</key>
            <string>No elements</string>
            <key>one</key>
            <string>One element</string>
            <key>other</key>
            <string>%llu elements</string>
        </dict>
    </dict>
</dict>
</plist>

To use the key:

Text("\(someUIntVarValue) elements")
Gravelly answered 26/8, 2020 at 21:26 Comment(6)
This has probably been only fixed in recent Xcode12 because it's not working in Xcode 11.5. Thanks for the tip thoughPrudery
Apologies for the confusion, it does work if I run the app, but I'm looking at making it work via Xcode Preview, which doesn't somehowPrudery
This is horrible, no one is going to rewrite all their string keys just to include the parameter in the parameter name. Especially since such files are usually used across platforms.Furcate
You can use NSLocalizedString or custom implementation of the localized strings if needed and do not lose environment abilities nonameplum.github.io/posts/…Weihs
Working with iOS' localization system after working in Android's much better system is so painful.Testosterone
this is not working with positional arguments. eg: Hello %1$@ my name is %2$@Hix

© 2022 - 2024 — McMap. All rights reserved.