如何解析只有一种语言在一个JSON文件的时间?



我有一个JSON文件,如下所示:

[
{
"id": 123,
"textEN": "something",
"textDE": "irgendwas"
}, 
...
]

我的环境中有一个结构体:

struct Something: Codable, Identifiable, Hashable {
var id: Int
var text: String
}

解析用户正在使用的语言的最好和/或最简单的方法是什么?我可以通过Locale.current.language.languageCode?.identifier查看用户设置语言。但是我应该如何总是只解析特定的语言呢?我考虑了以下方法,但偶然发现了一些问题:

  1. 解析所有不同的语言并在视图中使用切换用例。可以工作,但在我看来是非常非常糟糕的代码。
  2. 解析所有不同的语言,并在视图之前实现另一个逻辑层。在数据被视图使用之前,管理器或视图模型或其他将负责删除除用户翻译之外的所有翻译。应该有效,但有没有更好的选择?
  3. 以某种方式只解析和存储当前正在使用的数据中的一种语言。可能是最好的解决方案,但我没能让这个工作。我试图实现一个CodingKey,这是一个连接字符串("text"+语言代码),但这是不可能的,或者至少我不能弄清楚如何,使用一个变量作为CodingKey。

您可以尝试这种方法,使用动态密钥AnyKey(如评论和链接中提到的),一个init(from decoder: Decoder)和一个langKey只读取你想要的语言。

示例代码展示了一种非常简单的方法使用class LingoModel: ObservableObject读取json数据。根据自己的目的调整代码。

import Foundation
import SwiftUI
class LingoModel: ObservableObject {
@Published var langs = [Lingo]()

static var langKey = "textEN"

func fetchData(for lang: String) {
LingoModel.langKey = lang

let json = """
[
{
"id": 123,
"textEN": "something",
"textDE": "irgendwas"
},
{
"id": 124,
"textEN": "something2",
"textDE": "irgendwas2"
},
{
"id": 125,
"textEN": "something2",
"textDE": "irgendwas2",
"textJA": "日本語"
}
]
"""
do {
// simulated data from an API
let data = Data(json.utf8)
langs = try JSONDecoder().decode([Lingo].self, from: data)
} catch {
print(error)
}
}
}
struct ContentView: View {
@StateObject var model = LingoModel()
@State var selected: String = "textEN"

var body: some View {
VStack {
Picker("", selection: $selected) {
Text("textEN").tag("textEN")
Text("textDE").tag("textDE")
Text("textJA").tag("textJA")
}.pickerStyle(.segmented).frame(width: 222)
.onChange(of: selected) { lang in
model.fetchData(for: lang)
}
List(model.langs) { lingo in
Text(lingo.text)
}
}
.onAppear {
model.fetchData(for: selected)
}
}

}
struct Lingo: Codable, Identifiable, Hashable {
var id: Int
var text: String

struct AnyKey: CodingKey {
var stringValue: String
var intValue: Int?

init?(stringValue: String) {  self.stringValue = stringValue  }
init?(intValue: Int) { return nil } // not used
}

init(from decoder: Decoder) throws {
let container1 = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container1.decode(Int.self, forKey: .id)

self.text = ""
let container2 = try decoder.container(keyedBy: AnyKey.self)

if let theKey = container2.allKeys.first(where: {$0.stringValue == LingoModel.langKey}),
let txt = try? container2.decode(String.self, forKey: theKey) {
self.text = txt
}
}

}

要只解析用户正在使用的语言,您可以使用可解码结构体的init(from decoder: Decoder)方法来选择性地只解码用户设置的语言。

下面是一个示例实现:

let json = """
{
"id": 123,
"textEN": "something",
"textDE": "irgendwas"
}
""".data(using: .utf8)!
struct Something: Decodable, Identifiable, Hashable {
var id: Int
var text: String

enum CodingKeys: String, CodingKey {
case id, textEN, textDE
}
init(from decoder: Decoder) throws {

// change language value with `Locale.current.languageCode?.identifier`
let language = "en"

let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int.self, forKey: .id)

let textKeyForLanguage = language == "en" ? CodingKeys.textEN : CodingKeys.textDE
self.text = try container.decode(String.self, forKey: textKeyForLanguage)
}
}

在这个实现中,您使用CodingKeys枚举来定义JSON文件中属性的键。然后,在init(from decoder: Decoder)方法中,您首先获得用户选择的语言,然后使用它选择性地只解码与所选语言对应的属性。

您可以将默认的language值替换为Locale.current.language.languageCode?.identifier以获得用户选择的语言,但请确保处理未设置或未识别用户语言的情况。

请注意,我符合Decodable而不是Codable,所以如果你需要它是Encodable,你也必须实现func encode(to encoder: Encoder) throws

希望这对你有帮助!

最新更新