如何对依赖自动语法协议的字符串使用插值?

问题描述 投票:0回答:2

我正在尝试解决一个看似简单的问题:在 SwiftUI

Text
视图中向用户显示免费试用条款。我有一个单位字符串设置为
"Week"
和一个
value
,我可以从 1 切换到 2。为了处理复数,我利用了 iOS 15 上的自动语法协议。我的
Localizable.strings 中已经准备好了一个字符串
像这样文件:

"Subscription period: %lld %@" = "^[%lld ^[%@](grammar: { partOfSpeech: \"noun\" })](inflect: true)";

要构建字符串,我需要使用字符串插值来添加单词“free”。我知道在字符串文件中添加单词可以解决问题,但我不想这样做。我想普遍使用该字符串,不一定与免费试用有关。我不明白为什么我不能调用一些 init,向它传递一个密钥,并返回一个我可以根据需要进行插值的纯字符串。我已经尝试了很多方法,在所附的代码片段中展示了这些方法。要么找不到该字符串,要么未应用自动语法协议。似乎有

String.LocalizationValue.StringInterpolation
结构,但我不知道如何使用它,因为没有任何文档。我究竟做错了什么?我将不胜感激任何帮助!

struct ContentView: View {
    /// This value mimics what **StoreKit 2** returns for `Product.SubscriptionPeriod.Unit` in its `localizedDescription` on iOS 15.4.
    let unit = "Week"
    
    @State var value = 1
    
    var key: LocalizedStringKey {
        "Subscription period: \(value) \(unit)"
    }
    
    var plainStringKey: String {
        "Subscription period: \(value) \(unit)"
    }
    
    var body: some View {
        Form {
            Section {
                // Works fine without string interpolation.
                Text(key)
                    .foregroundColor(.green)
                
                // `NSLocalizedString` doesn't work and it shouldn't as per its docs.
                Text("\(NSLocalizedString(plainStringKey, comment: "")) free")
                    .foregroundColor(.red)
                
                // Doesn't see the string.
                Text("\(String(localized: String.LocalizationValue(stringLiteral: plainStringKey))) free")
                    .foregroundColor(.red)
                
                // This way also doesn't see the string, which is strange, because it should be just like the following way, which does see the string.
                Text("\(String(localized: String.LocalizationValue.init(plainStringKey))) free")
                    .foregroundColor(.red)
                
                // Sees the string (only if I pass literal, not the plainStringKey property), but doesn't apply automatic grammar agreement.
                Text("\(String(localized: String.LocalizationValue("Subscription period: \(value) \(unit)"))) free")
                    .foregroundColor(.red)
                
                
                // MARK: Bad solution:
                /*
                 - Doesn't work with Dynamic Type properly
                 - You have to approximate horizontal spacing
                 */
                
                HStack(spacing: 3) {
                    Text("Subscription period: \(value) \(unit)")
                        .textCase(.lowercase)
                    Text("free")
                }
                .foregroundColor(.orange)
            }
            
            Section {
                Stepper(value: $value, in: 1...2) {
                    Text("Value: \(value)")
                }
            }
        }
    }
}

您可以在此处下载示例项目。

ios swift string swiftui nslocalizedstring
2个回答
5
投票

我实际上非常接近这段代码:

Text("\(String(localized: String.LocalizationValue("Subscription period: \(value) \(unit)"))) free")

但是使用

String(localized:)
是不正确的。我猜是因为自动语法协议使用了markdown,这是
AttributedString
的特权。我们应该使用
AttributedString(localized:)
。但即便如此,它也不会改变,因为显然基金会存在一个错误。但一旦打上补丁,它就会像魅力一样发挥作用。

正确的解决方案是:

func freeTrialDuration() -> Text {
    // Use plain string.
    let duration: String = "^[\(value) ^[\(unit.lowercased())](grammar: { partOfSpeech: \"noun\" })](inflect: true)"
    // Use the following way to get the localized string.
    let localizedDuration = AttributedString(localized: String.LocalizationValue(duration))
    
    return Text("\(localizedDuration) free")
}

0
投票

我也遇到了与自动语法协议相关的同样问题。我尝试了你的答案,但就像你提到的

但即便如此,它也不会变形,因为显然基金会存在一个错误。但一旦打上补丁,它就会像魅力一样发挥作用。

现在已经 2024 年了,但仍然没有修补(遗憾的是)。所以我最终做出了这个决定

func description(for property: SubscriptionProperties) -> Text {
    switch property {
    case .subscription:
        let localizedStringKey = LocalizedStringKey("^[\(subscription) workout](inflect: true)")

        return Text(localizedStringKey)
    ....
}

这解决了我的问题!希望对你也有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.