【问题标题】:Enum with localized string in swiftswift中带有本地化字符串的枚举
【发布时间】:2015-03-28 14:50:42
【问题描述】:

我想使用带有本地化字符串的枚举,所以我喜欢这个,它可以工作,但是 这个解决方案的问题是:我无法从本地化字符串中轻松获取枚举值,我必须有钥匙才能做到:

let option = DietWithoutResidueOption(rawValue: "NoDiet")

如果不是我必须调用dietWithoutResidueOptionWith 方法来获取枚举值...:/

有更好的解决方案直接存储localizedString而不是枚举中的键?

谢谢

枚举

  enum DietWithoutResidueOption: String {
  case NoDiet = "NoDiet"
  case ThreeDays = "ThreeDays"
  case FiveDays  = "FiveDays"

  private func localizedString() -> String {
    return NSLocalizedString(self.rawValue, comment: "")
  }

  static func dietWithoutResidueOptionWith(#localizedString: String) -> DietWithoutResidueOption {
    switch localizedString {
    case DietWithoutResidueOption.ThreeDays.localizedString():
      return DietWithoutResidueOption.ThreeDays
    case DietWithoutResidueOption.FiveDays.localizedString():
      return DietWithoutResidueOption.FiveDays
    default:
      return DietWithoutResidueOption.NoDiet
    }
  }
}

Localizable.strings

"NoDiet" = "NON, JE N'AI PAS DE RÉGIME";
"ThreeDays" = "OUI, SUR 3 JOURS";
"FiveDays"  = "OUI, SUR 5 JOURS";

打电话

println(DietWithoutResidueOption.FiveDays.localizedString())

【问题讨论】:

  • 这是一个very good article,关于 Swift 中的本地化以实现健壮的架构

标签: ios swift enums localization


【解决方案1】:

试试我创建的这个协议,你可以像下面这样导入、使用它。

https://github.com/Wei18/ZWExt/blob/master/ZWExt/Classes/Protocol/Localizable.swift

enum SomeKey: String, Localizable {
  case MenuGreeting = "lb_menu_greeting"
  case HaveBook = "I have %@ books"
}

// Sample
let menuGreeting: String = SomeKey.MenuGreeting.localized()
let iHaveBoxes: String = SomeKey.HaveBook.localized([3])

/*
// You also can make it with html.
SomeKey.CustomCase.localizedHTML()
SomeKey.CustomCase.localizedHTML([])
*/

【讨论】:

  • 链接不存在
【解决方案2】:

这是我的例子

enum Localization: String {
    case appName = "app_name"
    case appOk = "app_ok"
    case appError = "app_error"
    case placeholderNoContent = "placeholder_no_content"
    case homeTitle = "home_title"

public func localized(args: CVarArg...) -> String {
    let localizedString = NSLocalizedString(self.rawValue, comment: "")
    return withVaList(args, { (args) -> String in
        return NSString(format: localizedString, locale: Locale.current, arguments: args) as String
    })
}
}

用法

self.homeTitleLabel = Localization.homeTitle.localized()

这个本地化枚举可以很容易地与字符串格式一起使用。

【讨论】:

    【解决方案3】:

    这是一个迟到的答案,但我刚刚与 Apple 工程师讨论了他们建议这样做的主题:

        enum LocalizedStrings {
            case title
    
            var localized: String {
                switch self {
                case .title:
                    return NSLocalizedString("My Title", comment: "My Comment")
                }
            }
        }
    

    在您的情况下,解决方案与原始代码没有太大区别:

        enum DietWithoutResidueOption {
            case NoDiet
            case ThreeDays
            case FiveDays
    
            var localizedString: String {
                switch self {
                case .NoDiet:
                    return NSLocalizedString("NoDiet", comment: "Some comment")
                case .ThreeDays:
                    return NSLocalizedString("ThreeDays", comment: "Some comment")
                case .FiveDays:
                    return NSLocalizedString("FiveDays", comment: "Some comment")
                }
            }
    
            static func dietWithoutResidueOptionWith(localizedString: String) -> DietWithoutResidueOption {
                switch localizedString {
                case DietWithoutResidueOption.ThreeDays.localizedString:
                    return DietWithoutResidueOption.ThreeDays
                case DietWithoutResidueOption.FiveDays.localizedString:
                    return DietWithoutResidueOption.FiveDays
                default:
                    return DietWithoutResidueOption.NoDiet
                }
            }
        }
    
    

    原因是他们不希望你将变量传递给 NSLocalizedString()。这与优化和解析字符串有关。想象一下 Xcode 在某个时候自己生成了 localizable.strings 文件,但它找不到字符串,因为它们是作为变量传递的。

    【讨论】:

      【解决方案4】:

      一个不错的方法是使用静态变量创建一个可本地化字符串的结构,如下所示:

      LocalizableStrings.swift

      struct LocalizableStrings {
          static let noDiet  = NSLocalizedString("NoDiet", comment: "")
          static let threeDays  = NSLocalizedString("ThreeDays", comment: "")
          static let fiveDays  = NSLocalizedString("FiveDays", comment: "")
      }
      

      Localizable.strings

      "NoDiet" = "NON, JE N'AI PAS DE RÉGIME";
      "ThreeDays" = "OUI, SUR 3 JOURS";
      "FiveDays"  = "OUI, SUR 5 JOURS";
      

      你的枚举看起来像这样:

      枚举

      enum DietWithoutResidueOption {
          case NoDiet,
          ThreeDays,
          FiveDays
      
          var description : String {
              get {
                  switch(self) {
                  case .NoDiet:
                      return LocalizableStrings.noDiet
                  case .ThreeDays:
                      return LocalizableStrings.threeDays
                  case .FiveDays:
                      return LocalizableStrings.fiveDays
                  }
              }
          }
      }
      

      因此,例如,要获取您的描述,您可以执行以下操作:

      DietWithoutResidueOption.NoDiet.description
      

      这种方法的好处是您可以将可本地化字符串的键放在一个文件中。因此,例如,如果您更改 Localizable.strings 文件上的 NoDiet 键,您只需要更新 LocalizableStrings.swift 文件,而不是我们有 NoDiet 的所有地方em> 键作为字符串。此外, 您冒着在使用它的某些文件中拼写错误 NoDiet 键的风险,并且您的代码将无错误地编译,同时使用 LocalizableStrings.swift 中的静态变量可以避免这种情况,因为您的代码将无法编译,您将看到一条错误消息,说明错误在哪里。

      【讨论】:

      • 我真的很喜欢你的方法,因为它使用了 Apple 的建议,只是对每个字符串使用了不同的 NSLocalizedString()!
      【解决方案5】:

      试试这个,它非常简单直接:

      enum ChoicesTitle: String {
          case choice1 = "Choice 1"
          case choice2 = "Choice 2"
          case choice3 = "Choice 3"
          case choice4 = "Choice 4"
          case choice5 = "Choice 5"
          case choice6 = "Choice 6"
      
          func localizedString() -> String {
              return NSLocalizedString(self.rawValue, comment: "")
          }
      
          static func getTitleFor(title:ChoicesTitle) -> String {
              return title.localizedString()
          }
      }
      

      你可以这样使用它:

      let stringOfChoice1: String = ChoicesTitle.getTitleFor(title: .choice1)
      

      希望这对你有用

      【讨论】:

      • 不要忘记将字符串的本地化版本添加到'Localizable.strings'中,否则将没有翻译版本。
      【解决方案6】:

      其他选择:

      枚举

      enum Title : String {
      
        case CEO = "CEOKey"
        case CTO = "CTOKey"
        case CFO = "CFOKey"
      
        private static let allTitles = [CEO, CTO, CFO]
      
        var localizedString: String {
          return NSLocalizedString(self.rawValue, comment: "")
        }
      
        init!(rawValue: String) {
          var keys =  Title.allTitles
          var filtered = keys.filter { $0.rawValue == rawValue }
      
          self = filtered.first!
        }
      
        init!(localizedString: String) {
          var keys =  Title.allTitles
          var filtered = keys.filter { $0.localizedString == localizedString }
      
          self = filtered.first!
        }
      }
      

      Localizable.strings

      "CEOKey" = "Chief Executive Officer";
      "CTOKey" = "Chief Technical Officer";
      "CFOKey" = "Chief Financial Officer";
      

      合约枚举:

      let option1 = Title.CFO
      let option2 = Title(rawValue: "CTOKey") // init from key
      let option3 = Title(localizedString: NSLocalizedString("CEOKey", comment: ""))  // init from value
      

      提取本地化字符串:

      println("option1 localized string : \(option1.localizedString)")
      println("option2 localized string : \(option2.localizedString)")
      println("option3 localized string : \(option3.localizedString)")
      

      输入

      option1 localized string : Chief Financial Officer
      option2 localized string : Chief Technical Officer
      option3 localized string : Chief Executive Officer
      

      如果未找到本地化字符串或键,此代码将生成异常

      【讨论】:

        【解决方案7】:

        您可以将任何StringLiteralConvertible, Equatable 类型用于RawValue 类型的enum

        那么,怎么样:

        import Foundation
        
        struct LocalizedString: StringLiteralConvertible, Equatable {
        
            let v: String
        
            init(key: String) {
                self.v = NSLocalizedString(key, comment: "")
            }
            init(localized: String) {
                self.v = localized
            }
            init(stringLiteral value:String) {
                self.init(key: value)
            }
            init(extendedGraphemeClusterLiteral value: String) {
                self.init(key: value)
            }
            init(unicodeScalarLiteral value: String) {
                self.init(key: value)
            }
        }
        
        func ==(lhs:LocalizedString, rhs:LocalizedString) -> Bool {
            return lhs.v == rhs.v
        }
        
        enum DietWithoutResidueOption: LocalizedString {
            case NoDiet = "NoDiet"
            case ThreeDays = "ThreeDays"
            case FiveDays  = "FiveDays"
        
            var localizedString: String {
                return self.rawValue.v
            }
        
            init?(localizedString: String) {
                self.init(rawValue: LocalizedString(localized: localizedString))
            }
        }
        

        使用它,您可以通过 3 种方式构造 DietWithoutResidueOption

        let option1 = DietWithoutResidueOption.ThreeDays
        let option2 = DietWithoutResidueOption(rawValue: "ThreeDays") // as Optional
        let option3 = DietWithoutResidueOption(localizedString: "OUI, SUR 3 JOURS")  // as Optional
        

        并使用以下命令提取本地化字符串:

        let localized = option1.localizedString
        

        【讨论】:

        • 将 'var 本地化字符串 ...' 放在 RawRepresentable 的扩展中是否更有意义,其中 RawValue 是 LocalizedString,因此您可以在所有使用 LocalizedString 作为其的枚举上免费获得它原始值类型?
        • 我刚刚和一位苹果工程师讨论了本地化问题,他们建议不要在 NSLocalizedString() 中传递变量,因为它会阻止自动发现字符串。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-28
        相关资源
        最近更新 更多