swiftswiftuienumslocalizationstring-catalog

How to get String Catalog to work with Swift Enum's Raw Values?


In SwiftUI I have a Picker (based on UISegmentedControl) that uses an enum for the cases (and strings) that it displays like so:

enum DayRange: String, CaseIterable, Identifiable {
    case fourteen = "14 Days"
    case ninety = "90 Days"
    case allTime = "All Time"
    
    var id: String { self.rawValue }
}

These cases are used in the logic on a reporting screen to determine date ranges etc.

But now I'm localizing the app, so...

Is it really true that it's impossible to use a string catalog (for purposes of localization) for these strings?

These strings are not showing automatically in the string catalog... and I'm not sure how I would refer to them from code even if they were there.

I timidly tried... this?:

enum DayRange: LocalizedStringKey, CaseIterable, Identifiable {
    case fourteen = "14 Days"
    case ninety = "90 Days"
    case allTime = "All Time"
    
    var id: LocalizedStringKey { self.rawValue }
}

But it says it's not identifiable anymore.


Solution

  • Just add a LocalizedStringKey property and return string literals from that property. This causes the strings to be added to the string catalog.

    enum DayRange: String, CaseIterable, Identifiable {
        case fourteen
        case ninety
        case allTime
        
        var localized: LocalizedStringKey {
            switch self {
            case .fourteen:
                "14 Days"
            case .ninety:
                "90 Days"
            case .allTime:
                "All Time"
            }
        }
        
        var id: String { self.rawValue }
    }
    

    Your second attempt causes the enum to not conform to Identifiable because Identifiable requires the type of id to be Hashable, but LocalizedStringKey is not Hashable, only Equatable.

    The enum itself is implicitly Hashable, so an alternative approach is to just use the enum itself as the id. Since each enum case has a unique raw value, this does not change the identities of the enum cases, compared to using the rawValue as the id.

    enum DayRange: LocalizedStringKey, CaseIterable, Identifiable {
        case fourteen = "14 Days"
        case ninety = "90 Days"
        case allTime = "All Time"
        
        var id: DayRange { self }
    }