问题
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 ...
回答1:
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";
回答2:
Apparently, a LocalizedStringKey
will automatically generate the localization key depending on the type of the values interpolated. For example, if you have the following Text
s
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)")
回答3:
I have built this extension to String to manage localization across my apps. You can simply use it like "history".localized
to get the localized string.
To apply replacements, use the method "my string %@".localized(withSubstitutions: "my substitution")
You can slice and dice to use what you want from the extension.
I have also maintained 2 constants let sameInBothLanguages: [String]
& let needTranslationsFor: [String]
to keep a record if there are strings which shouldn't be localized because they are same in both languages or to be sent out to content team for translations.
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
}
}
来源:https://stackoverflow.com/questions/62042521/localization-with-string-interpolation-in-swiftui