You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 17:21:09