主页 Swift 使用属性包装器实现应用本地化
Post
Cancel

Swift 使用属性包装器实现应用本地化

您好,Swift 开发者,在本文中,我想与您分享我的经验和知识,主要内容有属性包装器Property Wrapper)的使用,以及如何简化代码并使其易于维护。我会通过几个主题对此进行说明。

在 Swift 5.1 中,Apple 引入了属性包装器,它可以让我们在属性和访问逻辑(getter 和 setter)之间设置中间层。

下面的内容是在 @IBOutlet 变量内部使用属性包装器的简便方法来实现应用本地化。


优化下面这个基础版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
class NatureViewController: UIViewController {
  @IBOutlet private var label: UILabel! {
    didSet {
      label.title = NSLocalizedString("natureTitle", comment: "")
    }
  }
  
  @IBOutlet private var button: UIButton! {
    didSet {
      button.setTitle(NSLocalizedString("saveNatureButton", comment: ""), for: .normal)
    }
  }
}

我们可以用属性包装器 @Localized 改进代码,如下:

1
2
3
4
5
6
7
class NatureViewController: UIViewController {
  @Localized("natureTitle")
  @IBOutlet private var label: UILabel!
  
  @Localized("saveNatureButton")
  @IBOutlet private var button: UIButton!
}

这代码看起来很优雅,不是吗?下面让我们创建 @Localized 属性包装器。 将 key 当做枚举来使用会更好,如:@Localized(.natureTitle)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@propertyWrapper
struct Localized<T: Localizable> {
  private let key: LocalizationKey
  
  var wrappedValue: T? = nil {
    didSet {
      wrappedValue?.set(localization: key)
    }
  }
  
  init(_ key: LocalizationKey) {
    self.key = key
  }
}

为了能让更多的类型能够支持 Localizable 协议, 我们要实现 UILabelUIButton 的扩展方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protocol Localizable {
  func set(localization: LocalizationKey)
}

extension UIButton: Localizable {
  func set(localization key: LocalizationKey) {
    setTitle(key.string, for: .normal)
  }
}

extension UILabel: Localizable {
  func set(localization key: LocalizationKey) {
    text = key.string
  }
}

最后我们只需要实现 LocalizationKey:

1
2
3
4
5
6
7
8
9
10
11
enum LocalizationKey: String {
  case 
  natureTitle, 
  saveNatureButton
}

extension LocalizationKey {
  var string: String {
    NSLocalizedString(rawValue, comment: rawValue)
  }
}

我们可以直接用 raw 的值来表示相应的 key,String 类型默认遵守这个协议,所以只需要枚举中的值与 Localizable.strings 中的 key 保持一致就可以了。

最终的代码如下:

1
2
3
4
5
6
7
class NatureViewController: UIViewController {
  @Localized(.natureTitle)
  @IBOutlet private var label: UILabel!
  
  @Localized(.saveNatureButton)
  @IBOutlet private var button: UIButton!
}

本章结束!关于 @Localized 还有一些潜在功能:

  • 格式化字符串数据,并进行动态替换。
  • 能够确定来自指定的表单和资源包的字符串。

想了解更多关于属性包装器的知识,请阅读官方文档: Properties - The Swift Programming Language (Swift 5.2)

该博客文章由作者通过 CC BY 4.0 进行授权。

文章目录

Swift 中使用 Option Pattern 改善可选项的 API 设计

SwiftUI 滑动来解锁(slide to unlock)动画解析