Enum with localized string in swift
Solution 1
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
Solution 2
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
Solution 3
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.
Solution 4
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.
Solution 5
Ohter alternative :
Enum
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";
Constract enum :
let option1 = Title.CFO
let option2 = Title(rawValue: "CTOKey") // init from key
let option3 = Title(localizedString: NSLocalizedString("CEOKey", comment: "")) // init from value
Extract the localized strings :
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
This code will generate exception, if localized strings or keys not found
Related videos on Youtube
Comments
-
HamzaGhazouani almost 2 years
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())
-
Mendy about 5 yearsThis is a very good article about localization in Swift for a robust architecture
-
Sujananth about 2 yearsLocalizing a enum is a bad idea. Because you cannot convert a value in localizable file to the respective enum easily. The ID in the localizable may be unique, but the value will be changing and repeating.
-
-
NerdyTherapist almost 7 yearsYou must not forget to add the localized versions of the string to 'Localizable.strings', otherwise there would be no translated version.
-
Mark A. Donohoe about 6 yearsWouldn't it make more sense to put the 'var localizedString...' in an extension of RawRepresentable where RawValue is LocalizedString so you'd get it for free on all enums that use LocalizedString as their raw value type?
-
Sn0wfreeze almost 5 yearsI just talked to an Apple Engineer about localization and they recommend not to pass variables in NSLocalizedString() as it will stop the strings from beeing discovered automatically.
-
Sn0wfreeze almost 5 yearsI really like your approach as it uses Apple's recommendations and just uses a different NSLocalizedString() for every string!
-
Marek H almost 4 yearslink doesn't exists