Localization SwiftUI中的字符串插值本地化

Localization SwiftUI中的字符串插值本地化,localization,swiftui,Localization,Swiftui,我正在尝试本地化我的SwiftUI手表应用程序。 我对静态字符串没有任何问题。我在文本视图中使用LocalizedKeyString,并在Localizable.strings文件中添加翻译。 例如: Text("history") Text("startCustom \(format: "%.1f",customDistance)") 在Localizable.strings中: "history" = "Historique"; 结果: “历史性” 但是我还想使用插值来定位Sting。

我正在尝试本地化我的SwiftUI手表应用程序。 我对静态字符串没有任何问题。我在文本视图中使用LocalizedKeyString,并在Localizable.strings文件中添加翻译。 例如:

Text("history")
Text("startCustom \(format: "%.1f",customDistance)")
在Localizable.strings中:

"history" = "Historique";
结果: “历史性”

但是我还想使用插值来定位Sting。例如:

Text("history")
Text("startCustom \(format: "%.1f",customDistance)")
在Localizable.strings中,我尝试了不同的语法:

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

什么都不管用。
我找不到任何关于这方面的文档…

我已将此扩展构建到String以管理我的应用程序的本地化。您可以像
“history.localized”那样简单地使用它来获取本地化字符串

要应用替换,请使用方法“my string%@”。本地化(带有替换:“my substitution”)

您可以通过切片和骰子从扩展中使用所需的内容

我还维护了两个常量:
let sameinboth languages:[String]
&
let needTranslationsFor:[String]
,以记录是否存在不应本地化的字符串,因为它们在两种语言中相同,或者将发送给内容团队进行翻译

extension String {
    var localized: String {
        return localized(from: nil)
    }

    func localized(withSubstitutions substitutions: String...) -> String {
        return String(format: self.localized, arguments: substitutions)
    }

    func localized(from table: String?) -> String {
        let translatedString = getTranslatedString(fromTable: table)

        // No sense looking up the string in Release builds
        #if !DEBUG
            return translatedString
        #endif

        guard Locale.current.languageCode == "en" else {
            return translatedString
        }

        let otherLanguage = "es"

        // We can keep adding to this list temporarily in order to make the app actually run.  Every so often we will give this list to the content team and empty it once we get the translations back.
        let otherLanguageString = getTranslatedString(fromTable: table, inLanguage: otherLanguage)

        if otherLanguageString == self &&
            !sameInBothLanguages.contains(self) &&
            !needTranslationsFor.contains(self) {
            //swiftlint:disable:next no_nslocalizedstring
            assertionFailure("No Spanish version of localized string found for '\(self)'.  Please go to String+SA.swift and add this string to either the 'needTranslationsFor' or 'sameInBothLanguages' array.")
        }

        return translatedString
    }

    private func getTranslatedString(fromTable table: String?, inLanguage language: String) -> String {
        if let path = Bundle.main.path(forResource: language, ofType: "lproj"),
            let otherLanguageBundle = Bundle(path: path) {
            let otherLanguageString = getTranslatedString(fromTable: table, andBundle: otherLanguageBundle)

            return otherLanguageString
        }
        return self
    }

    private func getTranslatedString(fromTable table: String?, andBundle bundle: Bundle = Bundle.main) -> String {
        let translatedString = bundle.localizedString(forKey: self, value: self, table: table)

        return translatedString
    }
}

下面的简单示例可以正常工作(使用Xcode 11.4进行测试)

具有Localizable.string的

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

显然,
LocalizedStringKey
将根据插值的类型自动生成本地化密钥。例如,如果您有以下
Text
s

Text("title key")
Text("name key \("Club")")
Text("count key \(8)")
Text("price key \(6.25)")
您的Localizable.strings文件应该如下所示

"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";  
如果您想支持32位系统(iPhone 5或更早版本),请小心。在32位系统中,
Int
Int32
“Int32键\(Int32(8))”
的键是
“Int32键%d”
。您始终可以将整数转换为
Int64
,如
中的“count key\(Int64(8))”
以在不同的系统中强制执行一致的密钥

备注1:适用于想知道它是如何工作的人。当使用字符串文字或内插字符串,如<代码>“计数键”(8)“<代码> > <代码>文本< /代码>时,编译器将考虑字符串为<代码>本地化的String KEY < /C> >,因为<代码>文本< /代码>具有初始化器

init(_ key: LocalizedStringKey, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil),
LocalizedStringKey
符合
ExpressibleByStringLiteral
ExpressibleByStringInterpolation
,因此可以从字符串文字或字符串插值隐式初始化

备注2:如果您不确定密钥是什么,您可以通过在调试器中使用LocalizedStringKey自己获得答案,如下所示:

po LocalizedStringKey("count key \(8)")

它几乎完美,谢谢,但我仍然有一个bug:当我使用“fr”本地化时,它用英语而不是法语显示文本。所有其他的翻译都是对的,但这一个似乎只使用了英语本地化的。这只是Xcode和/或模拟器的一个bug。它在真实设备上运行良好。感谢您提供简单而有用的解决方案!!当使用这种方法时,在应用翻译应用程序后,以这种格式呈现文本:“Course de(“15.5”)km”有什么想法吗?为什么?你保存了我的答案非常好。如果其他人有问题,我最终发现使用Xcode 12.0.1时,SwiftUI iOS 14预览无法处理带有变量的字符串的本地化,例如文本(“计数键(x)”),但在模拟器或设备上运行时,相同的本地化确实可以正常工作。所以不要相信预览。@arcdale我发现预览有时有效有时无效,可能是一个bug。你建议使用调试器找到正确的格式是天才!解决了我的问题。
po LocalizedStringKey("count key \(8)")