Swift中带有本地化字符串的枚举

25
我想要在本地化字符串中使用枚举,所以我是这样做的,它有效,但是这种解决方案的问题是:我无法轻松地从本地化字符串中获取枚举值,我必须拥有该键才能做到:
let option = DietWithoutResidueOption(rawValue: "NoDiet")

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

是否有更好的解决方案直接存储本地化字符串而不是在枚举中使用键?

谢谢

枚举

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

可本地化字符串

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

呼叫

println(DietWithoutResidueOption.FiveDays.localizedString())

这是一篇非常棒的关于Swift本地化和鲁棒架构的文章。链接在此:https://medium.com/@mendibarouk/enhance-your-localized-capabilities-on-your-ios-applications-d3ba17138077 - Mendy
本地化枚举是一个不好的想法。因为你不能轻易地将可本地化文件中的值转换为相应的枚举。 本地化文件中的ID可能是唯一的,但其值会发生变化和重复。 - Sujananth
7个回答

20

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

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)

希望这对你有用


3
如果你没有在“Localizable.strings”中添加字符串的本地化版本,就不会出现翻译后的版本,这一点你不能忘记。 - NerdyTherapist

14
你可以使用任何实现了StringLiteralConvertibleEquatable协议的类型作为enumRawValue类型。
那么,我们如何使用呢?
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 localizedString...' 放在 RawRepresentable 的扩展中,其中 RawValue 是 LocalizedString,这样你就可以在所有使用 LocalizedString 作为原始值类型的枚举中免费获得它,这不是更有意义吗? - Mark A. Donohoe
我刚刚与一位苹果工程师讨论了本地化问题,他建议不要在 NSLocalizedString() 中传递变量,否则字符串将无法自动发现。 - Sn0wfreeze

11

这个回答有些迟,但我刚刚与 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在某个时刻自动生成本地化字符串文件,但找不到字符串,因为它们被作为变量传递。


2
一种好的方法是创建一个具有静态变量的本地化字符串结构体,就像这样: 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"键作为字符串的位置。此外,您还可以避免在某个文件中拼写"NoDiet"键错误并且您的代码将编译而不会出现错误。使用来自LocalizableStrings.swift的静态变量,您可以避免这种情况,因为您的代码将无法编译,并且您将看到一个错误消息,指出错误的位置。"最初的回答"

1
我真的很喜欢你的方法,因为它使用了苹果的建议,并且只是对每个字符串使用不同的NSLocalizedString()! - Sn0wfreeze

1
其他选项:

枚举

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

"Input"(输入)
option1 localized string : Chief Financial Officer
option2 localized string : Chief Technical Officer
option3 localized string : Chief Executive Officer

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

1
这是我的例子。
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()

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

0
请尝试使用我创建的这个协议,您可以像下面这样导入并使用它。

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([])
*/

链接不存在。 - Marek H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接