I have an app localizable in 2 languages. In SwiftUI-charts I get errors using LocalizedStringKey. Using String in stead of LocalizedStringKey works, but then the x- and y-axis values are not localized. Is there a way to localize these axis-values? Do I have to use LocalizedStringKey, if so how can I make this plottable?
My shortend code:
import SwiftUI
import Charts
enum PickerQuestions: LocalizedStringKey, CaseIterable { //with String the charts draws but no localization
case Q1 = "first question"
case Q2 = "second question"
case Q3 = "third question"
}
enum PickerCategory: LocalizedStringKey, Codable, CaseIterable { //idem
case picker1 = "not"
case picker2 = "a little"
case picker3 = "medium"
case picker4 = "very"
}
class PickerDataForBarChart: Identifiable {
let id = UUID()
var question: PickerQuestions
var category: PickerCategory
var percentage: Double
init(question: PickerQuestions, category: PickerCategory, percentage: Double) {
self.question = question
self.category = category
self.percentage = percentage
}
}
//stubdata
var chartDataStub: [PickerDataForBarChart] = [
.init(question: .Q1, category: .picker1, percentage: 50),
.init(question: .Q2, category: .picker2, percentage: 75),
.init(question: .Q3, category: .picker1, percentage: 25),
]
//the barchart
Chart(chartDataStub) {spec in
BarMark(
x: .value("Number", spec.percentage),
y: .value("Question", spec.question.rawValue) //error: Initializer 'init(x:y:width:height:stacking:)' requires that 'LocalizedStringKey' conform to 'Plottable'
)
.foregroundStyle(by: .value("Category", spec.category.rawValue)) //error: Instance method 'foregroundStyle(by:)' requires that 'LocalizedStringKey' conform to 'Plottable'
}
.chartForegroundStyleScale( //foreGroundStyle-array and scale-array have to be exactly the same!
domain: [PickerCategory.picker1.rawValue, PickerCategory.picker2.rawValue, PickerCategory.picker3.rawValue, PickerCategory.picker4.rawValue], //error: Referencing instance method 'chartForegroundStyleScale(domain:range:type:)' on 'Array' requires that 'LocalizedStringKey' conform to 'Plottable'
range: [Color.blue, Color.red, Color.yellow, Color.gray]
)
.frame(height: 350)
PS I use a workaround by checking for the device language setting and conditionally using a string-array for each language, but there must be a better way (I hope). Someone an idea?
You could change your enums to have raw type String
. Then add a computed property that returns the localized version of the raw value as per the answer to How to change LocalizedStringKey to String in SwiftUI.
For example, in the case of the enum PickerQuestions
:
enum PickerQuestions: String, CaseIterable {
case Q1 = "first question"
case Q2 = "second question"
case Q3 = "third question"
var localized: String {
let localizedKey = String.LocalizationValue(stringLiteral: rawValue)
return String(localized: localizedKey)
}
}
You can then pass .localized
to the chart components, instead of .rawValue
:
BarMark(
x: .value("Number", spec.percentage),
y: .value("Question", spec.question.localized)
)
.foregroundStyle(by: .value("Category", spec.category.localized))
With these translations:
"first question" = "Question One";
"second question" = "Question Two";
"third question" = "Question Three";
"not" = "Nope";
"a little" = "Possibly";
"medium" = "Maybe, maybe not";
"very" = "Yes";
...it works like this: