在我过去几年使用的所有框架中,我一直对代码中的本地化读取方式感到不满。定义一个"键"或者过于复杂。 (如在Swing中)或感觉太脆(如在Rails中)。此外,工具支持(尤其是自动完成等)总是有很多不足之处。
所以我开始看看我能在Swift中实现目标的程度。我大致试图实现以下目标:
.strings
文件中获取本地化,而不仅仅是Localizable.strings
以下是我提出的内容(在Playground中,所以我只发出NSLocalizedString
次调用,而不是在代码中实际调用它。)
import UIKit
import Foundation
protocol Localizable {
var key : String { get }
func localized() -> String
}
extension Localizable {
func localized() -> String {
return "NSLocalizedString(\(key))"
}
}
prefix operator §
enum Default : String, Localizable {
case hello
case world = "this planet"
var key : String { get { return rawValue } }
static prefix func §(str: Default) -> String {
return str.localized()
}
}
Default.hello.localized()
§.hello
§.world
适用于Localizable.strings
并对其他文件中的字符串进行如下扩展:
protocol TabLocalizable : Localizable {
var table: String { get }
}
extension TabLocalizable {
func localized() -> String {
return "NSLocalizedString(\(key), table:\(table))"
}
}
enum WorldTable : String, TabLocalizable {
case earth
case proximaCentauriB = "Proxima Centauri B"
var key : String { get { return rawValue } }
var table : String { get { return "worldTable" } }
static prefix func §(str: WorldTable) -> String {
return str.localized()
}
}
WorldTable.proximaCentauriB.localized()
§.earth
§.proximaCentauriB
我定义keys
的主要方式是enums
,因为它们显然需要最少量的语法来定义新密钥。一个简单的
case newKey
就足够了,您唯一需要的就是.strings
文件中的相应定义。对于您的密钥中可能包含空格的现有.strings
文件,您必须有点冗长,但
case spacedKey = "Spaced Key"
我认为并不算太糟糕。定义键很容易,并使用值
Default.world.localized()
仍感觉不如NSLocalizedString("world“)
那么脆弱。但是,它并不能完全满足我对“最小化”的定义。事实证明,我们可以通过使用前缀运算符来进一步缩短代码。因为这些必须从一个"奇怪的"我选择使用§
作为我的操作符,因为它在语言中似乎没有特定的用途,尽管它在大多数键盘布局上都很容易获得,它暗示"与语言有关" 34。
这导致
§.world
作为本地化的字符串引用,在简洁方面很难被击败。所以现在我所有的密钥都经过了编译时间测试,自动完成功能可以找到现有密钥。
但是我对此有一点小问题:为了使自动完成工作,我必须将(几乎相同的)运算符定义放入每个enum
定义中。这似乎是一个很小的代价,它可能是,但我仍然想问一下是否有人知道只需要定义一次。
把
static prefix func §(str: Localizable) -> String {
return str.localized()
}
进入Localizable
协议的定义起初看起来是个好主意,但是
§.hello
将失败
error: type 'Localizable' has no member 'hello'
甚至是电话
§Default.hello
将失败
error: generic parameter 'Self' could not be inferred
这指向了我可能会'是一种在正确的位置使用聪明的prefix func §
参数定义Self
的方法,但我看不出它是如何完成的。我希望Swift仍然有一些微妙之处,允许这种类型的"泛型运算符"以某种方式。
如果你在某些方面找到更多的通用性,那么如果你在评论中指出这一点会更好。