Skip to content

Commit b16f95f

Browse files
committed
feat: 补充逻辑。
1 parent c3bc872 commit b16f95f

3 files changed

Lines changed: 164 additions & 2 deletions

File tree

Translator/CSVHelper/CSVHelper.swift

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,153 @@
77
//
88

99
import Foundation
10+
import CSV
11+
12+
private let keyTitles = ["key","Key","KEY"]
13+
private let keyDesc = "备注"
14+
15+
func handleCSVError(message: String) -> HandleError {
16+
return HandleError(title: "CSV解析", message: message)
17+
}
18+
19+
extension String {
20+
/// 移除字符串左右空白
21+
func removeWhitespace() -> String {
22+
return self.trimmingCharacters(in: .whitespaces)
23+
}
24+
}
25+
26+
public struct CSVHelper {
27+
func csvReader(url: URL) throws -> CSVReader {
28+
guard let stream = InputStream(url: url) else {
29+
throw handleCSVError(message: "读取文件流失败")
30+
}
31+
let reader = try CSVReader(stream: stream)
32+
return reader
33+
}
34+
/// 从csv流中 转换为对象。
35+
func parseCSVFile(reader: CSVReader) throws -> (models: [LanguageFileModel], errorInfo: [HandleError]) {
36+
guard let keyRow = findKeyRow(reader: reader) else {
37+
throw handleCSVError(message: "未找到包含 Key 的行")
38+
}
39+
debugPrint("表头数据:\(keyRow)\n")
40+
// 检查是否包含 Key 列
41+
guard let keyIndex = keyRow.firstIndex(where: {keyTitles.contains($0.removeWhitespace())}) else {
42+
throw handleCSVError(message: "不存在 key 列")
43+
}
44+
// 检查是否有重复title
45+
let titleSet = Set.init(keyRow)
46+
guard titleSet.count == keyRow.count else {
47+
throw handleCSVError(message: "存在相同的title, titles:\(keyRow)")
48+
}
49+
// 备注Index
50+
let descColumnIndex = keyRow.firstIndex { title in
51+
return isDescTitle(title)
52+
};
53+
var languageFiles: [LanguageFileModel] = keyRow.compactMap { title in
54+
if isIgnoreTitle(title) {
55+
return nil
56+
} else {
57+
var model = LanguageFileModel()
58+
model.languageName = title.removeWhitespace()
59+
return model
60+
}
61+
}
62+
var errors: [HandleError] = []
63+
// 接着一行一行读取
64+
while reader.next() != nil {
65+
var key = ""
66+
guard let current = reader.currentRow else {
67+
errors.append(handleCSVError(message: "reader.currentRow 异常"))
68+
continue
69+
}
70+
// 往每个多语言添加 key value 和备注
71+
// 备注
72+
var desc = "";
73+
if let index = descColumnIndex {
74+
desc = current[index]
75+
}
76+
// key value
77+
for (index,title) in keyRow.enumerated() {
78+
if keyTitles.contains(title.removeWhitespace()) {
79+
key = current[keyIndex]
80+
continue
81+
}
82+
guard !isIgnoreTitle(title) else {
83+
continue
84+
}
85+
let value = current[index]
86+
87+
if key.isEmpty && value.isEmpty {
88+
// 空白行
89+
continue
90+
}
91+
if value.isEmpty {
92+
errors.append(handleCSVError(message: "\(key)缺少\(title)翻译"))
93+
}
94+
if key.isEmpty {
95+
errors.append(handleCSVError(message: "\(value)缺少对应key"))
96+
}
97+
let item = LanguageItem(key: key, value: value, desc: desc)
98+
if let index = languageFiles.firstIndex(where: {$0.languageName == title}) {
99+
languageFiles[index].items.append(item)
100+
} else {
101+
errors.append(handleCSVError(message: "\(key)=\(value)未找到对应多语言Model(title:\(title)"))
102+
}
103+
104+
}
105+
}
106+
return (languageFiles , errors)
107+
}
108+
}
109+
// MARK: Private Method
110+
private extension CSVHelper {
111+
/// 是否是备注列
112+
func isDescTitle(_ title: String) -> Bool {
113+
let title = title.removeWhitespace();
114+
guard !title.isEmpty else {
115+
return false
116+
}
117+
return title == keyDesc
118+
}
119+
func isIgnoreTitle(_ title:String) -> Bool{
120+
let title = title.trimmingCharacters(in: .whitespaces);
121+
guard !title.isEmpty else {
122+
return true
123+
}
124+
guard !isDescTitle(title) else {
125+
return true;
126+
}
127+
var ignoreTitles = ["序号"] //跳过的列
128+
ignoreTitles.append(contentsOf: keyTitles)
129+
return ignoreTitles.contains(title)
130+
}
131+
/// 查找包含 Key 的行
132+
/// 注意:执行了 next, 会移动 reader。
133+
func findKeyRow(reader: CSVReader) -> [String]? {
134+
var header: [String] = []
135+
if let headerRow = reader.headerRow {
136+
header = headerRow
137+
}
138+
/// 必须要包含 Key 列
139+
let keyHeader = header.filter {keyTitles.contains($0.removeWhitespace())}
140+
guard keyHeader.isEmpty else {
141+
return keyHeader
142+
}
143+
header = []
144+
while (reader.next() != nil) {
145+
guard let current = reader.currentRow else {
146+
break
147+
}
148+
let count = current.filter {keyTitles.contains($0.removeWhitespace())}.count
149+
if count > 0 {
150+
return current
151+
}
152+
}
153+
if header.isEmpty {
154+
return nil
155+
} else {
156+
return header
157+
}
158+
}
159+
}
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
//
2-
// Error.swift
2+
// HandleError.swift
33
// Translator
44
//
55
// Created by PandaEye on 2025/2/28.
66
// Copyright © 2025 PandaEye. All rights reserved.
77
//
88

99
import Foundation
10+
struct HandleError: Error {
11+
let title: String?
12+
let message: String
13+
init(title: String?, message: String) {
14+
self.title = title
15+
self.message = message
16+
}
17+
init(message: String) {
18+
self.title = nil
19+
self.message = message
20+
}
21+
}

Translator/Classes/String+Ext.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ extension String {
2525
func removeFileHeader() -> String {
2626
return replacingOccurrences(of: "file://", with: "")
2727
}
28-
28+
/// 移除括号
2929
func removeBraces() -> String? {
3030
return replacingOccurrences(of: "", with: "(").components(separatedBy: "(").first
3131
}

0 commit comments

Comments
 (0)