Swift中的NSLocalizedString等效项是什么?


228

有Swift的等效项NSLocalizedString(...)吗?在中Objective-C,我们通常使用:

NSString *string = NSLocalizedString(@"key", @"comment");

如何在Swift中实现相同目标?我发现了一个功能:

func NSLocalizedString(
    key: String,
    tableName: String? = default,
    bundle: NSBundle = default,
    value: String = default,
    #comment: String) -> String

但是,它很长,根本不方便。


2
最好是创建较短版本的代码片段:NSLocalizedString(“”,comment:“”)...我喜欢扩展解决方案,但是问题是genstrings不会将这些字符串捕获到翻译文件中。
Matej Ukmar

3
在Swift 3中,您可以使用NSLocalizedString("Cancel", comment: "Cancel button title")默认值。我认为这很方便。
LShi

这是关于本地化(字符串扩展,不同的字符串表,甚至复数)一个很好的文章:medium.com/@marcosantadev/...
莱特曼

这是一篇关于Swift本地化的非常好的文章,介绍了一个健壮的体系结构medium.com/@mendibarouk/…–
Mendy

Answers:


373

我使用下一个解决方案:

1)创建扩展名:

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

2)在Localizable.strings文件中:

"Hi" = "Привет";

3)使用实例:

myLabel.text = "Hi".localized

请享用!;)

--upd:-

对于带有注释的情况,您可以使用以下解决方案:

1)扩展名:

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

2)在.strings文件中:

/* with !!! */
"Hi" = "Привет!!!";

3)使用:

myLabel.text = "Hi".localized(withComment: "with !!!")

92
唯一的问题是您将无法使用该genstrings实用程序生成您的.strings文件。
Ned

9
好主意!我还通过更改为func localized(comment: String = "") -> String使其变得更小巧并带有可选注释:)
Gui Moura

2
任何想法如何genstrings与此一起使用?
克里斯

48
每个人都对这个答案感到非常兴奋,但是BIG问题(对于使用多种语言的任何严肃的项目而言)是,这完全使您对翻译后的消息的管理混乱了,因为genstrings仅适用于传递给NSLocalizedString的文字字符串。使用这种聪明的解决方法,您将失去使用该genstrings工具更新.strings文件的能力,至少对我而言,这意味着我将无法使用这种简化方法。
Erik van der Neut'3

14
我在github.com/marmelroy/Localize-Swift中发现了实现此出色的解决方案。genstrings的问题也可以通过作者自定义的python脚本解决。我不是作家。
Tomek Cejner '16

279

NSLocalizedString在斯威夫特的世界同样存在。

func NSLocalizedString(
    key: String,
    tableName: String? = default,
    bundle: NSBundle = default,
    value: String = default,
    #comment: String) -> String

tableNamebundlevalue参数均标有default该装置的同时调用该函数我们可以忽略这些参数的关键字。在这种情况下,将使用其默认值。

这得出一个结论,该方法调用可以简化为:

NSLocalizedString("key", comment: "comment")

Swift 5-没什么变化,仍然可以像这样工作。


44
注释不能为零是唯一的区别,对于简短版本,自动完成功能远非直观。
Marcin 2014年

1
这不再起作用了,我得到一个错误,指出没有使用足够的参数。
Apps 4 U

2
上述内容在Xcode 6.3,Swift 1.2中与Objective-c有所不同,并不是正确的,注释(如Marcin所述)不能为nil,但可以为“”(空)。
尼尔

2
nil / empty注释使以后很难在字符串文件中重定位该字符串。如果没有其他要求,请在用作注释的位置添加类/文件名。
约翰

这是正确的答案。一旦Apple确实为Swift对其进行了更新,Xcode将能够将该API自动转换为其新的Swift API,并且其他任何操作都不会中断。即使当前在Xcode的Refractor菜单(v 11.4.1)中,也有一个Wrap in NSLocalizedString选项可以使事情变得非常简单,只需突出显示文本,右键单击并选择菜单项即可。
伊桑·艾伦

28

现有答案的变体:

Swift 5.1:

extension String {

    func localized(withComment comment: String? = nil) -> String {
        return NSLocalizedString(self, comment: comment ?? "")
    }

}

然后,您可以简单地使用它(带有或不带有注释):

"Goodbye".localized()
"Hello".localized(withComment: "Simple greeting")

请注意genstrings该解决方案无法使用。


14

通过使用这种方法,可以为不同类型(即Int或自定义类,如CurrencyUnit等)创建不同的实现。也可以使用genstrings实用程序扫描此方法调用。只需将例程标志添加到命令

genstrings MyCoolApp/Views/SomeView.swift -s localize -o .

延期:

import UIKit

extension String {
    public static func localize(key: String, comment: String) -> String {
        return NSLocalizedString(key, comment: comment)
    }
}

用法:

String.localize("foo.bar", comment: "Foo Bar Comment :)")

这个答案是惊人的,应该更多地支持!如果您希望避免引入另一个库,那么这是我到目前为止找到的最简单的解决方案。这是一个很好的本地解决方案。
cgossain

6

Swift 3版本:)...

import Foundation

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

6

实际上,您可以使用两个阶段来翻译Swift项目中的文本:

1)第一个阶段是使用旧方法创建所有可翻译字符串:

NSLocalisedString("Text to translate", comment: "Comment to comment")

1.1)然后,您应该使用genstrings生成Localizable.strings:

$ genstrings *swift

2)之后,您应该使用此答案

2.1)根据正则表达式使用XCode的“查找和替换”选项。对于给定的示例(如果您没有评论),正则表达式将为:

NSLocalizedString\((.*)\, comment:\ \"\"\) 

并替换为

$1.localized

或(如果您有意见)

NSLocalizedString\((.*)\, comment:\ (.*)\)

并替换为

$1.localizedWithComment(comment: $2)

您可以根据需要自由使用正则表达式和其他扩展名组合。通常的方法是将整个过程分为两个阶段。希望能有所帮助。


1
抱歉,我在这里没有很多答案。与使用相比,该方法有什么好处NSLocalizedString("Cancel", comment: "Cancel button title")
LShi

1
@LShi有些人抱怨说,它NSLocalizedString看起来不像应该看起来的那样快捷。String.localized另一方面,它看起来更快速,但是您无法将gesntrings其与公用程序一起使用,该实用程序通常用于简化国际化工作。我的观点是,将两种方法混合使用非常容易。因此,主要是可读性问题。
GYFK '02

如果您需要再进行一轮会genstrings怎样?您是否全部替换.localizedNSLocalizedString
Cristik

5

针对总是忽略“注释”的情况创建了一个小的辅助方法。更少的代码更易于阅读:

public func NSLocalizedString(key: String) -> String {
    return NSLocalizedString(key, comment: "")
}

只要将其放在任何地方(类之外),Xcode就会找到此全局方法。


12
这是不好的做法。除非您自己进行所有翻译,否则建议使用注释并提供帮助。
耶利米

即使您正在翻译自己,这些评论也将很有帮助,尤其是在大型项目中。
shim

4

最好的方法可能就是这里

fileprivate func NSLocalizedString(_ key: String) -> String {
    return NSLocalizedString(key, comment: "")
}

import Foundation
extension String {
    static let Hello = NSLocalizedString("Hello")
    static let ThisApplicationIsCreated = NSLocalizedString("This application is created by the swifting.io team")
    static let OpsNoFeature = NSLocalizedString("Ops! It looks like this feature haven't been implemented yet :(!")
}

然后可以像这样使用它

let message: String = .ThisApplicationIsCreated
print(message)

对我来说这是最好的,因为

  • 硬编码的字符串位于一个特定的文件中,因此,要更改它的那一天真的很容易
  • 比每次在文件中手动键入字符串更容易使用
  • genstrings仍然可以工作
  • 您可以添加更多扩展,例如每个视图控制器扩展一个,以保持整洁

3
需要注意的是,以上述方式定义的字符串是静态字符串。在iOS设置应用中更改语言后,应重新启动该应用。如果没有,请自行重新启动以查看更改。由于我们可以一次(而不是在需要时)初始化所有字符串,因此也可能会占用内存。
iDevAmit

2
我认为最好在这里使用计算属性,就像这样static var Hello: String = { return NSLocalizedString("Hello") }
梦想的艺术

Downvoted因为它不遵循斯威夫特命名指南
Cristik

3

在开发SDK时。您需要一些额外的操作。

1)像往常一样在YourLocalizeDemoSDK中创建Localizable.strings

2)在YourLocalizeDemo中创建相同的Localizable.strings

3)找到YourLocalizeDemoSDK 的捆绑路径

Swift4

// if you use NSLocalizeString in NSObject, you can use it like this
let value = NSLocalizedString("key", tableName: nil, bundle: Bundle(for: type(of: self)), value: "", comment: "")

Bundle(for: type(of: self))帮助您在YourLocalizeDemoSDK中找到捆绑软件。如果Bundle.main改用,则会得到错误的值(实际上,它是与键相同的字符串)。

但是,如果要使用OX博士提到的String扩展名。您还需要做更多。原点扩展名看起来像这样。

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

众所周知,我们正在开发一个SDK,Bundle.main将获得YourLocalizeDemo的捆绑包。那不是我们想要的。我们需要YourLocalizeDemoSDK中的捆绑软件。这是快速找到它的技巧。

在YourLocalizeDemoSDK的NSObject实例中运行以下代码。然后,您将获得YourLocalizeDemoSDK的URL。

let bundleURLOfSDK = Bundle(for: type(of: self)).bundleURL
let mainBundleURL = Bundle.main.bundleURL

打印两个URL,您会发现我们可以在mainBundleURL的基础上构建bundleURLofSDK。在这种情况下,它将是:

let bundle = Bundle(url: Bundle.main.bundleURL.appendingPathComponent("Frameworks").appendingPathComponent("YourLocalizeDemoSDK.framework")) ?? Bundle.main

字符串扩展名将是:

extension String {
    var localized: String {
        let bundle = Bundle(url: Bundle.main.bundleURL.appendingPathComponent("Frameworks").appendingPathComponent("YourLocalizeDemoSDK.framework")) ?? Bundle.main
        return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "")
    }
}

希望能帮助到你。


2

我创建了自己的genstrings类工具,用于使用自定义翻译功能提取字符串

extension String {

    func localizedWith(comment:String) -> String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: comment)
    }

}

https://gist.github.com/Maxdw/e9e89af731ae6c6b8d85f5fa60ba848c

它将解析所有的swift文件,并将代码中的字符串和注释导出到.strings文件。

可能不是最简单的方法,但有可能。


1

虽然这不能解决缩短的问题,但是可以帮助我组织消息,但我为错误消息创建了一个结构,如下所示

struct Constants {
    // Error Messages
    struct ErrorMessages {
        static let unKnownError = NSLocalizedString("Unknown Error", comment: "Unknown Error Occured")
        static let downloadError = NSLocalizedString("Error in Download", comment: "Error in Download")
    }
}

let error = Constants.ErrorMessages.unKnownError

这样,您可以组织消息并使genstring工作。

这是使用的genstrings命令

find ./ -name \*.swift -print0 | xargs -0 genstrings -o .en.lproj

1

在单元测试中的用法:

这是一个简单的版本,可以扩展到不同的用例(例如,使用tableNames)。

public func NSLocalizedString(key: String, referenceClass: AnyClass, comment: String = "") -> String 
{
    let bundle = NSBundle(forClass: referenceClass)
    return NSLocalizedString(key, tableName:nil, bundle: bundle, comment: comment)
}

像这样使用它:

NSLocalizedString("YOUR-KEY", referenceClass: self)

或像这样加上评论:

NSLocalizedString("YOUR-KEY", referenceClass: self, comment: "usage description")

1
忽略评论是不好的做法。
何塞

@José感谢您的评论。该代码只是作为一个想法,而不是作为复制和粘贴的模板。但是我添加了添加注释的选项;)
GatoCurioso

1

这是对“ .localized”方法的改进。首先添加类扩展名,因为这将有助于您以编程方式设置的任何字符串:

extension String {
    func localized (bundle: Bundle = .main, tableName: String = "Localizable") -> String {
        return NSLocalizedString(self, tableName: tableName, value: "\(self)", comment: "")
    }
}

您以编程方式设置的字符串的示例用法:

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

现在,Xcode的情节提要翻译文件使文件管理器变得混乱,也无法很好地处理情节提要的更新。更好的方法是创建一个新的基本标签类,并将其分配给所有情节提要标签:

class BasicLabel: UILabel {
    //initWithFrame to init view from code
    override init(frame: CGRect) {
      super.init(frame: frame)
      setupView()
    }

    //initWithCode to init view from xib or storyboard
    required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      setupView()
    }

    //common func to init our view
    private func setupView() {
        let storyboardText = self.text
        text = storyboardText?.localized()
    }
}

现在,假设您已为其提供了翻译,则在情节提要中添加并为其提供默认默认值的每个标签将自动进行翻译。

您可以对UIButton做同样的事情:

class BasicBtn: UIButton {
    //initWithFrame to init view from code
    override init(frame: CGRect) {
      super.init(frame: frame)
      setupView()
    }

    //initWithCode to init view from xib or storyboard
    required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      setupView()
    }

    //common func to init our view
    private func setupView() {
        let storyboardText = self.titleLabel?.text
        let lclTxt = storyboardText?.localized()
        setTitle(lclTxt, for: .normal)
    }
}

0

当您将短语相同的英语翻译为不同的另一种语言(由于性别,动词变位或词尾变化)时,Swift中最简单的 NSString形式(在所有情况下均有效)是以下三个参数。例如,英语短语“以前是”,不同的是俄语翻译的“权重”的情况下(“предыдущ ий был”)和“腰”(“предыдущ ая был а ”)。

在这种情况下,您需要为一个源进行两种不同的转换(就WWDC 2018中推荐的XLIFF工具而言)。您不能使用两个参数NSLocalizedString来实现它,其中“ previous was”对于“ key”和英文翻译(即值)都是相同的。唯一的方法是使用三个参数形式

NSLocalizedString("previousWasFeminine", value: "previous was", comment: "previousWasFeminine")

NSLocalizedString("previousWasMasculine", value: "previous was", comment: "previousWasMasculine")

其中的键(“ previousWasFeminine”和“ previousWasMasculine”)不同。

我知道一般的建议是翻译整个词组,但是有时太费时又不方便。


-1

使用默认语言进行本地化:

extension String {
func localized() -> String {
       let defaultLanguage = "en"
       let path = Bundle.main.path(forResource: defaultLanguage, ofType: "lproj")
       let bundle = Bundle(path: path!)

       return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.