如何在SwiftUI Charts中本地化X轴与Y轴的数值?
解决方案
最优方案:分离数据标识与本地化文本
核心思路是用枚举的固定字符串标识作为图表的Plottable键,把本地化逻辑移到图表显示层处理,既满足SwiftUI Charts对Plottable类型的要求,又能实现完美本地化,还能避免语言切换导致的图表分组异常。
步骤1:重构枚举类型
将枚举rawValue改为固定标识字符串(非本地化文本),新增计算属性获取本地化后的文本:
import SwiftUI import Charts // 用固定标识作为rawValue,本地化逻辑放在计算属性中 enum PickerQuestions: String, CaseIterable { case Q1 = "question_1" case Q2 = "question_2" case Q3 = "question_3" // 获取本地化文本 var localized: String { String(localized: LocalizedStringKey(rawValue)) } } enum PickerCategory: String, Codable, CaseIterable { case picker1 = "category_not" case picker2 = "category_a_little" case picker3 = "category_medium" case picker4 = "category_very" var localized: String { String(localized: LocalizedStringKey(rawValue)) } } 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 } } // 测试数据不变 var chartDataStub: [PickerDataForBarChart] = [ .init(question: .Q1, category: .picker1, percentage: 50), .init(question: .Q2, category: .picker2, percentage: 75), .init(question: .Q3, category: .picker1, percentage: 25), ]
步骤2:配置本地化字符串文件
在Localizable.strings中添加对应语言的翻译:
- 英文(en.lproj/Localizable.strings):
"question_1" = "first question"; "question_2" = "second question"; "question_3" = "third question"; "category_not" = "not"; "category_a_little" = "a little"; "category_medium" = "medium"; "category_very" = "very"; - 中文(zh-Hans.lproj/Localizable.strings):
"question_1" = "第一个问题"; "question_2" = "第二个问题"; "question_3" = "第三个问题"; "category_not" = "完全没有"; "category_a_little" = "有一点"; "category_medium" = "中等"; "category_very" = "非常";
步骤3:修改图表代码实现本地化显示
用枚举rawValue作为Plottable键,通过图表修饰器替换显示文本为本地化内容:
Chart(chartDataStub) { spec in BarMark( x: .value("Number", spec.percentage), // 用rawValue作为Plottable标识,保证分组稳定 y: .value("Question", spec.question.rawValue) ) .foregroundStyle(by: .value("Category", spec.category.rawValue)) } // 自定义Y轴标签,显示本地化文本 .chartYAxis { AxisMarks(position: .leading) { value in AxisGridLine() AxisTick() AxisLabel { if let questionKey = value.as(String.self), let question = PickerQuestions(rawValue: questionKey) { Text(question.localized) } } } } // 自定义图例标签,显示本地化文本 .chartLegend { LegendEntry( label: Text(PickerCategory.picker1.localized), symbol: LegendSymbol(shape: .circle.fill, color: .blue) ) LegendEntry( label: Text(PickerCategory.picker2.localized), symbol: LegendSymbol(shape: .circle.fill, color: .red) ) LegendEntry( label: Text(PickerCategory.picker3.localized), symbol: LegendSymbol(shape: .circle.fill, color: .yellow) ) LegendEntry( label: Text(PickerCategory.picker4.localized), symbol: LegendSymbol(shape: .circle.fill, color: .gray) ) } .chartForegroundStyleScale( domain: PickerCategory.allCases.map(\.rawValue), range: [Color.blue, Color.red, Color.yellow, Color.gray] ) .frame(height: 350)
备选方案:让LocalizedStringKey遵循Plottable协议
如果一定要直接使用LocalizedStringKey作为Plottable类型,可以通过扩展实现,但此方法存在潜在风险:本地化后的字符串会作为图表分组依据,切换语言后可能导致图表数据分组逻辑变化。
扩展代码
extension LocalizedStringKey: Plottable { public var primitivePlottable: String { // 返回本地化后的字符串作为Plottable原始值 String(localized: self) } public init?(primitivePlottable: String) { // 从本地化字符串反向初始化,实际场景中可能需要调整逻辑 self.init(primitivePlottable) } }
使用说明
扩展后可直接在图表中使用LocalizedStringKey类型的枚举原始值,无需修改原有数据结构:
Chart(chartDataStub) { spec in BarMark( x: .value("Number", spec.percentage), y: .value("Question", spec.question.rawValue) ) .foregroundStyle(by: .value("Category", spec.category.rawValue)) } .chartForegroundStyleScale( domain: PickerCategory.allCases.map(\.rawValue), range: [Color.blue, Color.red, Color.yellow, Color.gray] ) .frame(height: 350)
内容的提问来源于stack exchange,提问作者Etihv
相关产品推荐
相关产品推荐

