在Swift中NSLocalizedString等价于什么?

是否有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

但是,它很长,一点也不方便。

125320 次浏览

NSLocalizedString也存在于Swift的世界中。

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

tableNamebundlevalue参数用default关键字标记,这意味着在调用函数时可以省略这些参数。在本例中,将使用它们的默认值。

这导致一个结论,方法调用可以简化为:

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

斯威夫特5 -没有变化,仍然像那样工作。

我使用下一个解决方案:

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

享受吧!;)

——乌利希期刊指南:

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

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 !!!")
通过使用这种方式,可以为不同类型(即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 :)")

为总是忽略“comment”的情况创建了一个小的helper方法。更少的代码更容易阅读:

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

只要把它放在任何地方(类之外),Xcode就会找到这个全局方法。

有助于在单元测试中使用:

这是一个简单的版本,可以扩展到不同的用例(例如使用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")

Swift 3版本:)…

import Foundation


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

当你翻译,说从英语,其中一个短语是相同的,到另一种语言,它是不同的(因为性别,动词的变位或变化)最简单的< < em > / em > NSString形式在Swift工作在所有情况下是三个参数一。例如,英语短语“previous was”的“weight”(“предыдущий б л”)和“waist”(“предыдущая б л __abc3”)的翻译与俄语不同。

在这种情况下,一个Source需要两种不同的翻译(就WWDC 2018推荐的XLIFF工具而言)。你不能实现它与两个参数NSLocalizedString,其中“previous was”将是相同的“键”和英文翻译(即值)。唯一的方法就是使用三论点形式

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


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

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

我知道一般的建议是将短语整体翻译,然而,有时这太费时和不方便。

可能最好的方法是这个在这里

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仍然可以工作
  • 你可以添加更多的扩展,比如每个视图控制器一个扩展来保持整洁

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

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

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

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

$ genstrings *swift

2)之后,你应该使用这个回答

使用你的XCode“Find and Replace”基于正则表达式的选项。 对于给定的示例(如果您没有注释),正则表达式将是:

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

并将其替换为

$1.localized

或者(如果你有意见的话)

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

并将其替换为

$1.localizedWithComment(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文件中。

也许这不是最简单的方法,但这是可能的。

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

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

现有答案的变体:

斯威夫特5.1:

extension String {


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


}

然后你可以简单地使用它,带或不带注释:

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

genstrings不能用于此解决方案。

当你在开发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代替,你将得到一个错误的值(实际上它将是与键相同的字符串)。

但如果你想使用牛博士中提到的String扩展名。你需要做更多的事情。原点扩展是这样的。

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

正如我们所知,我们正在开发一个SDK, Bundle.main将获得YourLocalizeDemo的bundle。这不是我们想要的。我们需要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

而String扩展名将是:

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: "")
}
}

希望能有所帮助。

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

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: "")
}
}

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

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)
}
}

除了伟大的扩展在这里,如果你懒得找到和替换旧的NSLocalizedString,你可以打开find &在Xcode中replace,在find部分你可以写NSLocalizedString\(\(".*"\), comment: ""\),然后在replace部分你需要写$1.localized来改变项目中所有的NSLocalizedString"blabla".localized

扩展:

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

用途:"_YOUR_STRING_NAME_".localized()