Generics 仅使用一个运算符定义的Swift国际化字符串

Generics 仅使用一个运算符定义的Swift国际化字符串,generics,swift3,autocomplete,localization,operators,Generics,Swift3,Autocomplete,Localization,Operators,在我过去几年使用的所有框架中,我总是对本地化读取代码的方式感到不满。要么定义“键”过于复杂(如在Swing中),要么感觉太脆(如在Rails中)。此外,工具支持(尤其是autocomplete或类似工具)总是有很多需要改进的地方 因此,我开始考虑在Swift中我能实现多少目标。我大致尝试实现以下目标: 让编译时检查代码中的键常量,而不是使用字符串参数甚至宏的过程调用 能够以最小的语法麻烦定义新键,同时保持编译时安全 能够从不同的.strings文件中获取本地化,而不仅仅是可本地化的.strin

在我过去几年使用的所有框架中,我总是对本地化读取代码的方式感到不满。要么定义“键”过于复杂(如在Swing中),要么感觉太脆(如在Rails中)。此外,工具支持(尤其是autocomplete或类似工具)总是有很多需要改进的地方

因此,我开始考虑在Swift中我能实现多少目标。我大致尝试实现以下目标:

  • 让编译时检查代码中的键常量,而不是使用字符串参数甚至宏的过程调用
  • 能够以最小的语法麻烦定义新键,同时保持编译时安全
  • 能够从不同的
    .strings
    文件中获取本地化,而不仅仅是
    可本地化的.strings
  • 能够以最小的语法开销调用可本地化字符串,同时在Xcode中保持自动完成
  • 允许表示现有的转换表(其键中可能有空格)
下面是我的想法(在操场上,我只是发出
NSLocalizedString
调用,而不是像在代码中那样实际调用它)

它适用于
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
我定义
的主要方法是
枚举
,因为它们显然需要最少的语法来定义新键。简单的

case newKey
这就足够了,您只需要在
.strings
文件中有一个相应的定义。对于键中可能有空格的现有
.strings
文件,您必须稍微详细一点,但是

case spacedKey = "Spaced Key"
我觉得还不错。定义关键点非常简单,并将值用作

Default.world.localized()
仍然比
NSLocalizedString(“world”)
感觉不那么脆弱。但是,它并不完全满足我对“最小麻烦”的定义。事实证明,我们可以通过使用前缀运算符来进一步缩短代码。因为它们必须以“奇怪”开头“我选择将字符§§§用作我的运算符,因为它在语言中似乎没有特定的用途,尽管它在大多数键盘布局中都很容易找到,并且它暗指“与语言有关”

这导致了

§.world
作为一个本地化的字符串引用,很难在简洁性上击败它。所以现在我所有的键都经过了编译时测试,自动补全在查找现有键方面发挥了神奇的作用

然而,我有一个小小的困扰点:为了让自动完成工作,我必须在每个
enum
定义中加入(几乎相同的)操作符定义。这似乎是一个很小的代价,而且可能是,但我仍然想问,是否有人知道一种只需定义一次的方法

放置

static prefix func §(str: Localizable) -> String {
    return str.localized()
}
本地化
协议的定义中,首先看起来是个好主意,但是

§.hello
将以失败告终

error: type 'Localizable' has no member 'hello'
error: generic parameter 'Self' could not be inferred
甚至电话

§Default.hello
将以失败告终

error: type 'Localizable' has no member 'hello'
error: generic parameter 'Self' could not be inferred
这为我指出了一个方向,即“可能”有一种方法可以定义
前缀func§
,在正确的位置使用一个巧妙的
Self
参数,但我看不出该如何实现。我希望Swift仍有一些微妙之处,可以在某种程度上允许这种类型的“泛型运算符”


如果你在某一点上发现更多的泛型,那么最好在评论中指出这一点。

尝试全局
前缀func§(str:T)->String
@user28434这看起来很有希望。它至少可以覆盖
§Default.hello
,但它将在
§.world
上失败,并出现
错误:无法推断泛型参数“T”§.world
。这似乎有点奇怪,只要没有“真正的”歧义(在这一点上可以理解)。对于
之后的所有值,错误都是相同的,因此完成显然不起作用。