Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum with localized string in swift

I want to use enumeration with localized string, so I do like this, it works, but the problem of this solution is : I can't get easily enum value from localized string, I must have the key to do it :

let option = DietWithoutResidueOption(rawValue: "NoDiet")

If not I must to call dietWithoutResidueOptionWith method to get enum value... :/

There are a better solution to store directly localizedString and not keys in enum ?

Thanks

Enumeration

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

call

println(DietWithoutResidueOption.FiveDays.localizedString())
like image 373
HamzaGhazouani Avatar asked Jan 29 '15 11:01

HamzaGhazouani


4 Answers

Try this, it's pretty simple and straight forward:

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

And you could use it like this:

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

Hope this works for you

like image 186
Septronic Avatar answered Nov 17 '22 01:11

Septronic


You can use any StringLiteralConvertible, Equatable type for RawValue type of enum.

So, how about:

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

Using this, you can construct DietWithoutResidueOption by 3 ways:

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

and extract the localized string with:

let localized = option1.localizedString
like image 28
rintaro Avatar answered Nov 17 '22 01:11

rintaro


this is a late answer, but I just had a chat with Apple Engineers about that topic they recommend to do it that way:

    enum LocalizedStrings {
        case title

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

In your case the solution would be not much different from the original code:

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

The reason is that they don't want you to pass variables into NSLocalizedString(). This has something to do with optimization and parsing the strings. Imagine Xcode generating the localizable.strings file on it's own at some point, but it could not find the strings, because they are passed as variables.

like image 11
Sn0wfreeze Avatar answered Nov 17 '22 02:11

Sn0wfreeze


A nice approach is to create a struct of Localizable Strings with static variables like so:

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

And your enum would look like that:

Enum

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

So, for instance, to get your description you can do like below:

DietWithoutResidueOption.NoDiet.description

The good thing about this approach is that you put the keys of your localizable strings on a single file. So, for instance, if you change the NoDiet key on your Localizable.strings file you only need to update the LocalizableStrings.swift file, instead of all the places where we have the NoDiet key as a string. Furthermore, you take the risk of spelling wrong the NoDiet key in some file where it is being used and your code will compile with no errors, meanwhile using a static variable from LocalizableStrings.swift you can avoid that, as your code will not compile and you will see an error message saying where the error is.

like image 2
Mateus Forgiarini da Silva Avatar answered Nov 17 '22 00:11

Mateus Forgiarini da Silva