如何在Swift中使用NSLocalizedString函数和变量?

105

我正在使用NSLocalizedString来本地化我的应用程序。当我导入XLIFF文件时,大部分正常运行,但是有些不行,某些字符串没有本地化。我已经注意到问题出在包含一些变量的NSLocalizedString中:

NSLocalizedString(" - \(count) Notifica", comment: "sottotitolo prescrizione per le notifiche al singolare")
或者
NSLocalizedString("Notifica per \(medicina!) della prescrizione \(prescription!)\nMemo: \(memoTextView.text)", comment: "Messaggio della Local Notification")

也许这不是处理这种东西的正确语法。 有人可以向我解释如何用Swift实现吗?


1
这是一篇关于Swift本地化的非常好的文章,适用于强大的架构。 - Mendy
8个回答

166
你可以在NSLocalizedString中使用sprintf格式参数,因此你的示例可以是这样的:
let myString = String(format: NSLocalizedString(" - %d Notifica", comment: "sottotitolo prescrizione per le notifiche al singolare"), count)

6
在Localizable.string文件中,它是什么样子? - Van Du Tran
同Obj-C一样:"-%d Notifica" = "-%d Notifica"; - ReDetection
4
我该如何替换字符串?我尝试使用%s修饰符,但不起作用 =\ - igrek
18
请使用“%@”来替换字符串。 - Yeehaw
4
这些格式参数的参考资料可以在https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html找到。 - Shaun Dychko
你能告诉我在 NSLocalizedString() 中使用注释参数的作用吗? - lpd

114
在 WWDC2014 “使用 Xcode 6 进行本地化” 的第 412 次会议中,用 Swift 实现正确的方法如下:
String.localizedStringWithFormat(
    NSLocalizedString(" - %d Notifica",
    comment: "sottotitolo prescrizione per le notifiche al singolare"),
    count)

请注意:localizedStringWithFormat 方法将返回的字符串的 local 属性设置为其第一个参数所指定的值:

  • 该方法不会对任何内容进行翻译。
  • 这种混淆源于NSLocalizedString 的错误命名。
  • 它本应该被命名为 NSTranslatedString 或者 NSTranslatable (而不是 NSLocalizedString)。

4
你为什么需要使用 NSLocalizedString(...)? 它不是已经在 String.localizedStringWithFormat(...) 的实现中发生了吗? - Yitzchak
3
请查看(https://dev59.com/DF8d5IYBdhLWcg3w-mMk)本站提供的LocalizedStringWithFormat函数是一个用于在iOS及Mac OS平台上进行本地化字符串处理的函数。它能够帮助程序员更简单地将一个变量替换到本地化字符串模板中。该函数会接收两个参数,第一个参数是本地化字符串模板,第二个参数是要插入到模板中的变量。函数会返回一个新的字符串,其中包含了已经被格式化和本地化过的内容。使用这个函数时,需要注意在本地化字符串文件中预先定义好要替换的变量,并且保证传入函数的变量类型和数量与本地化字符串模板中定义的一致。 - Mark
2
谢谢,我问完之后就看到了。这对其他人来说也会非常有帮助,所以谢谢。 - Yitzchak

26

我采用了创建字符串扩展的方法,因为我有许多需要本地化的字符串。

extension String {
    var localized: String {
        return NSLocalizedString(self, comment:"")
    }
}

在代码中进行本地化,使用以下方法:

self.descriptionView.text = "Description".localized

对于包含动态变量的字符串,请注意以下内容:

self.entryTimeLabel.text = "\("Doors-open-at".localized) \(event.eventStartTime)"

为不同语言(例如:阿拉伯语和英语)在字符串文件中声明字符串。

输入图片说明 输入图片说明

希望这会有所帮助!


5
但在我看来,你只是把时间附加到字符串上。如果你的本地化字符串是像门在%@开放这样的话,你的解决方案还能起作用吗? - Houman
2
感谢您包含对 Localizable.strings 的引用。不过,我认为 @Houman 的担忧是合理的。 - Matt
这并不是好的做法,正如Houman所说,但这是一种通用的字符串连接方式。 - trusk
1
这不是一个好主意,因为它假设“doors open at”文本将在每种语言中都在时间值之前出现,但这并不一定正确。最好使用localizedStringWithFormat,这样如果需要,您可以改变插入值的位置。 - mginn
1
这个答案完全是错误的!在某些语言中,您可能需要不同的子字符串顺序来插入坏字符,但您不应硬编码顺序。 - Gargo
显示剩余2条评论

16

这里是我在String中使用的一个扩展,它添加了一个带有可变参数的localizeWithFormat函数。

extension String {

     func localizeWithFormat(arguments: CVarArg...) -> String{
        return String(format: self.localized, arguments: arguments)        
     }
            
     var localized: String{
         return Bundle.main.localizedString(forKey: self, value: nil, table: "StandardLocalizations")
     }
}

使用方法:

let siriCalendarText = "AnyCalendar"
let localizedText = "LTo use Siri with my app, please set %@ as the default list on your device reminders settings".localizeWithFormat(arguments: siriCalendarTitle)

只需小心不要使用与String相同的函数和属性名称。我通常为所有我的框架函数使用3个字母的前缀。


16

我尝试了上面的解决方案,但是下面的代码对我有效。

SWIFT 4

extension String {

    /// Fetches a localized String
    ///
    /// - Returns: return value(String) for key
    public func localized() -> String {
        let path = Bundle.main.path(forResource: "en", ofType: "lproj")
        let bundle = Bundle(path: path!)
        return (bundle?.localizedString(forKey: self, value: nil, table: nil))!
    }


    /// Fetches a localised String Arguments
    ///
    /// - Parameter arguments: parameters to be added in a string
    /// - Returns: localized string
    public func localized(with arguments: [CVarArg]) -> String {
        return String(format: self.localized(), locale: nil, arguments: arguments)
    }

}

// variable in a class
 let tcAndPPMessage = "By_signing_up_or_logging_in,_you_agree_to_our"
                                     .localized(with: [tAndc, pp, signin])

// Localization File String
"By_signing_up_or_logging_in,_you_agree_to_our" = "By signing up or logging in, you agree to our \"%@\" and \"%@\" \nAlready have an Account? \"%@\"";

2

我为UILabel编写了相同的函数。

extension UILabel {
    
    func setLocalizedText(key: String) {
        self.text = key.localized
    }
    
    func setLocalizedText(key: String, arguments: [CVarArg]) {
        self.text = String(format: key.localized, arguments: arguments)
    }
}

如果您想的话,也可以将此“localized”属性移动到UILabel中。
extension String {
        
    var localized: String{
        return Bundle.main.localizedString(forKey: self, value: nil, table: nil)
    }
}

我的本地化

"hi_n" = "Hi, %@!";

使用如下方式:

self.greetingLabel.setLocalizedText(key: "hi_n", arguments: [self.viewModel.account!.firstName])
// Shows this on the screen -> Hi, StackOverflow!

Swift 如何知道在你的字符串扩展中有两个 "setLocalizedText",该选择哪一个? - Robert Brax
@RobertBrax 它将根据你传递的参数数量来判断。 - OhhhThatVarun

0
我建议编写一个自定义的全局函数,而不是使用扩展,因为genstrings只是解析源代码中带有文字字面量的NSLocalizedString。这意味着你将无法从源代码中自动生成.strings文件,如果使用扩展的解决方案。
func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String, with arguments: CVarArg...) -> String {
    let localizedString = Foundation.NSLocalizedString(key, tableName: tableName, bundle: bundle, value: value, comment: comment)
    return String.localizedStringWithFormat(localizedString, arguments)
}

-4

我创建了一个String扩展,因为我有很多需要本地化字符串

extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
}

例如:

let myValue = 10
let anotherValue = "another value"

let localizedStr = "This string is localized: \(myValue) \(anotherValue)".localized
print(localizedStr)

6
这种方法的一个明显缺点是你必须手动提取字符串并发送给翻译人员,因为“编辑器 > 导出本地化…”不能自动捕获它们。 - Jason Moore
根据@JasonMoore的建议,我认为这不是正确的方法。 - Yuchen
@JasonMoore 完全同意你的观点。你们有人找到解决方案了吗? - gasparuff
我不知道为什么这个解决方案被评为负分:(。而且几乎下面的嵌套解决方案是相同的,但它得到了正分。 - Amr Angry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接