Skip to content

Commit df58ea1

Browse files
committed
feat: 版本功能更新。
1 parent c2ede33 commit df58ea1

27 files changed

Lines changed: 792 additions & 42 deletions

Translator.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
947CD8A52D6F220C00847AED /* Test.strings in Resources */ = {isa = PBXBuildFile; fileRef = 947CD8A32D6F220C00847AED /* Test.strings */; };
2323
947CD8AE2D70118C00847AED /* LanguageItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 947CD8AD2D70118C00847AED /* LanguageItem.swift */; };
2424
947CD8B02D70120300847AED /* LanguageFileModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 947CD8AF2D70120300847AED /* LanguageFileModel.swift */; };
25+
94B121912DDC165000CD14D7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 94B121902DDC165000CD14D7 /* README.md */; };
2526
94C2A4A02817EFA300E46F4A /* TranslatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2A49F2817EFA300E46F4A /* TranslatorTests.swift */; };
2627
94D9AA3F2D793A35004501F5 /* CSVHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D9AA3E2D793A35004501F5 /* CSVHelper.swift */; };
2728
94D9AA422D797227004501F5 /* 多语言翻译模板_数据异常.xlsx in Resources */ = {isa = PBXBuildFile; fileRef = 94D9AA402D797227004501F5 /* 多语言翻译模板_数据异常.xlsx */; };
@@ -62,6 +63,7 @@
6263
947CD8A42D6F220C00847AED /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Test.strings; sourceTree = "<group>"; };
6364
947CD8AD2D70118C00847AED /* LanguageItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageItem.swift; sourceTree = "<group>"; };
6465
947CD8AF2D70120300847AED /* LanguageFileModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageFileModel.swift; sourceTree = "<group>"; };
66+
94B121902DDC165000CD14D7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
6567
94C2A49D2817EFA300E46F4A /* TranslatorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TranslatorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6668
94C2A49F2817EFA300E46F4A /* TranslatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslatorTests.swift; sourceTree = "<group>"; };
6769
94D9AA3E2D793A35004501F5 /* CSVHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CSVHelper.swift; sourceTree = "<group>"; };
@@ -115,6 +117,7 @@
115117
3C0B910622F2D91000F16E13 /* Translator */ = {
116118
isa = PBXGroup;
117119
children = (
120+
94B121902DDC165000CD14D7 /* README.md */,
118121
94E191042D797EFE00EC4D65 /* UpdateStringsHelper */,
119122
947CD8A92D70111200847AED /* CSVHelper */,
120123
3C6E342222F56CCD00403D4C /* Classes */,
@@ -289,6 +292,7 @@
289292
files = (
290293
3C6E344122F5878000403D4C /* InfoPlist.strings in Resources */,
291294
94D9AA462D797250004501F5 /* 多语言翻译模板_数据异常.csv in Resources */,
295+
94B121912DDC165000CD14D7 /* README.md in Resources */,
292296
94D9AA472D797250004501F5 /* 多语言翻译模板_数据正常.csv in Resources */,
293297
3C6E343A22F56CCE00403D4C /* Assets.xcassets in Resources */,
294298
3C6E343922F56CCE00403D4C /* Localizable.strings in Resources */,

Translator/CSVHelper/CSVHelper.swift

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,29 @@ public struct CSVHelper {
3333
}
3434
/// 从csv流中 转换为对象。
3535
func parseCSVFile(reader: CSVReader) throws -> (models: [LanguageFileModel], errorInfo: [HandleError]) {
36-
guard let keyRow = findKeyRow(reader: reader) else {
36+
guard let tempKeyRow = findKeyRow(reader: reader) else {
3737
throw handleCSVError(message: "未找到包含 Key 的行")
3838
}
39+
// 删除中文 ( )
40+
let keyRow = tempKeyRow.map({deleteChinese($0).removeWhitespace()})
3941
debugPrint("表头数据:\(keyRow)\n")
4042
// 检查是否包含 Key 列
4143
guard let keyIndex = keyRow.firstIndex(where: {keyTitles.contains($0.removeWhitespace())}) else {
4244
throw handleCSVError(message: "不存在 key 列")
4345
}
46+
4447
// 检查是否有重复title
45-
let titleSet = Set.init(keyRow)
46-
guard titleSet.count == keyRow.count else {
47-
throw handleCSVError(message: "存在相同的title, titles:\(keyRow)")
48+
var titleDict = [String: Int]()
49+
keyRow.forEach { item in
50+
if let titleCount = titleDict[item] {
51+
titleDict[item] = titleCount + 1
52+
} else {
53+
titleDict[item] = 1
54+
}
55+
}
56+
let duplicateDict = titleDict.filter({$0.value > 1 && $0.key != ""})
57+
guard duplicateDict.count == 0 else {
58+
throw handleCSVError(message: "存在相同的title, titles:\(duplicateDict.keys)")
4859
}
4960
// 备注Index
5061
let descColumnIndex = keyRow.firstIndex { title in
@@ -55,7 +66,8 @@ public struct CSVHelper {
5566
return nil
5667
} else {
5768
var model = LanguageFileModel()
58-
model.languageName = title.removeWhitespace()
69+
let name = deleteChinese(title).removeWhitespace() // 删除空白,删除中文
70+
model.languageName = name
5971
return model
6072
}
6173
}
@@ -94,7 +106,7 @@ public struct CSVHelper {
94106
if key.isEmpty {
95107
errors.append(handleCSVError(message: "\(value)缺少对应key"))
96108
}
97-
let item = LanguageItem(key: key, value: value, desc: desc)
109+
let item = LanguageItem(key: key.removeWhitespace(), value: value.removeWhitespace(), desc: desc)
98110
if let index = languageFiles.firstIndex(where: {$0.languageName == title}) {
99111
languageFiles[index].items.append(item)
100112
} else {
@@ -138,7 +150,7 @@ private extension CSVHelper {
138150
/// 必须要包含 Key 列
139151
let keyHeader = header.filter {keyTitles.contains($0.removeWhitespace())}
140152
guard keyHeader.isEmpty else {
141-
return keyHeader
153+
return keyHeader.map({return $0.removeWhitespace()})
142154
}
143155
header = []
144156
while (reader.next() != nil) {
@@ -147,13 +159,20 @@ private extension CSVHelper {
147159
}
148160
let count = current.filter {keyTitles.contains($0.removeWhitespace())}.count
149161
if count > 0 {
150-
return current
162+
return current.map({return $0.removeWhitespace()})
151163
}
152164
}
153165
if header.isEmpty {
154166
return nil
155167
} else {
156-
return header
168+
return header.map({return $0.removeWhitespace()})
157169
}
158170
}
171+
/// 删除String中的中文 和 ( )
172+
func deleteChinese(_ string: String) -> String {
173+
var str = string.replacingOccurrences(of: "\\p{Han}", with: "", options: .regularExpression)
174+
str = str.replacingOccurrences(of: "", with: "")
175+
str = str.replacingOccurrences(of: "", with: "")
176+
return str
177+
}
159178
}

Translator/Classes/HomeController.swift

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class HomeController: NSViewController {
3333
@IBOutlet weak var stringsFileNameTextField: NSTextField!
3434
@IBOutlet weak var insertKeyTextField: NSTextField!
3535

36-
36+
/// 本地地址,存 error.log, strings的
3737
var localPath: URL?
3838
let csvHelper: CSVHelper = CSVHelper()
3939
/// 自动插入或者更新 strings
@@ -114,13 +114,17 @@ class HomeController: NSViewController {
114114
savePathField.stringValue = url.absoluteString.urlDecoded().removeFileHeader()
115115
}
116116
@IBAction func parseAutoInsertButtonTapped(_ sender: NSButton) {
117+
// TODO: - LWF: 待优化, 将英文也添加到结果 strings 中
117118
// 检查合法性
118119
let insertKey = self.insertKeyTextField.stringValue.removeWhitespace()
119120
guard !insertKey.isEmpty else {
120121
showAlert(title: "请填写插入key")
121122
return
122123
}
123-
guard let url = openPanel.url else {
124+
guard localPath != nil else {
125+
showAlert(title: Localized.pleaseSetTheStorageDirectoryFirst)
126+
return }
127+
guard openPanel.url != nil else {
124128
showAlert(title: Localized.failedToOpenFile)
125129
return
126130
}
@@ -132,7 +136,19 @@ class HomeController: NSViewController {
132136
// 开始对其他语言插入
133137
_ = self.autoInsertStrings(paths: stringsFilePaths, after: insertKey)
134138
} catch let error as HandleError {
135-
showAlert(title: "自动导入异常",msg: error.message)
139+
let msg = error.message
140+
Log.shared.error(msg)
141+
if let path = localPath {
142+
Log.shared.save(basePath: path.absoluteString.urlDecoded().removeFileHeader())
143+
let result = showAlert(title: "自动导入异常",msg: msg, doneTitle: "去检查错误日志")
144+
if (result) {
145+
NSWorkspace.shared.open(path)
146+
} else {
147+
debugPrint("打开失败:\(path.absoluteString)")
148+
}
149+
} else {
150+
showAlert(title: "自动导入异常",msg: msg);
151+
}
136152
} catch {
137153

138154
}
@@ -259,7 +275,7 @@ extension HomeController {
259275
if key.isEmpty {
260276
Log.shared.error("\(value)缺少对应key")
261277
}
262-
var result = "\"\(key)\" = \"\(Self.replaceSpecial(value))\";"
278+
var result = "\"\(Self.replaceSpecial(key))\" = \"\(Self.replaceSpecial(value))\";"
263279
if (descr.count > 0) {
264280
let describeArray = descr.components(separatedBy: "\n")
265281
var describe = ""
@@ -423,12 +439,7 @@ extension HomeController {
423439
/// 删除单个语言文件
424440
private func deleteSingleLanguageFile(paths:[String]) {
425441
for item in paths {
426-
var pathStr = item
427-
if #available(macOS 13.0, *) {
428-
pathStr = item.replacing("/\(localizableFileName)", with: "", maxReplacements: 1)
429-
} else {
430-
showAlert(title: "macOS 版本过低,应该大于 13.0")
431-
}
442+
let pathStr = item.replacingOccurrences(of: "/\(localizableFileName)", with: "")
432443
guard !pathStr.isEmpty else {
433444
return
434445
}
@@ -489,27 +500,50 @@ extension HomeController {
489500
if #available(macOS 13.0, *) {
490501
var successPath:[Path] = []
491502
var errorMsg = "自动解析插入失败\n"
503+
// 先创建 LocalizableAll.strings 文件,记录每个语言结果,如果全部成功,则删除。
504+
var textFile: TextFile!
505+
if let localizalbleAllFileURL = localPath?.appending(component: "AutoInsertLocalizableResult.strings"),
506+
let path = Path(url: localizalbleAllFileURL) {
507+
if path.exists {
508+
try path.deleteFile()
509+
}
510+
try? path.createFile()
511+
textFile = TextFile(path: path)
512+
try "// 自动插入多语言处理结果\n" |>> textFile
513+
}
492514
// 真正插入
493515
for path in paths {
494516
let languageName = path.parent.fileNameWithoutExtension
517+
var stringsFileText = "\n\n// MARK: - \(languageName)";
495518
if let aimFileModel = result.models.first(where: {$0.languageName.lowercased() == languageName.lowercased()}) {
496-
if let error = updateStringsHelper.insertOtherStrings(aimFileModel, to: path.rawValue, after: key) {
519+
if let error = updateStringsHelper.insertOtherStrings(aimFileModel, to: path.rawValue, after: key, scopeComment: self.commentsTextField.stringValue.removeWhitespace()) {
497520
errorMsg += error.message + "\n"
521+
stringsFileText += "\n// 自动插入失败:\n// \(error.message)\n"
522+
let stringsText = stringsText(aimFileModel)
523+
stringsFileText += "\n\(stringsText)"
498524
} else {
499525
successPath.append(path)
526+
stringsFileText += "\n// 自动插入成功, 请前往 git 版本控制检查。"
500527
}
501528
} else {
502529
// 没有找到对应多语言列
503-
errorMsg += "在csv 中没有找到对应语种\(languageName)翻译\n"
530+
let msg = "在csv 中没有找到对应语种\(languageName)翻译\n"
531+
errorMsg += msg
532+
stringsFileText += "\n// 自动插入失败:\(msg)"
504533
}
534+
try stringsFileText |>> textFile
505535
}
536+
var shouldOpenFile = false;
506537
if successPath.isEmpty {
507-
showAlert(title: "所有多语言插入失败,手动处理", msg: errorMsg, doneTitle: "确定")
538+
shouldOpenFile = showAlert(title: "所有多语言插入失败,请手动处理", msg: "请前往AutoInsertLocalizableResult.strings文件查看", doneTitle: "去处理")
508539
} else if successPath.count == paths.count {
509540
// 所有都成功
510-
showAlert(title: "所有多语言插入成功", doneTitle: "确定")
541+
shouldOpenFile = showAlert(title: "所有多语言插入成功", doneTitle: "确定")
511542
} else {
512-
showAlert(title: "部分多语言插入成功,手动处理", msg: errorMsg, doneTitle: "确定");
543+
shouldOpenFile = showAlert(title: "多语言插入部分成功,部分失败,请手动处理", msg: "请前往AutoInsertLocalizableResult.strings文件查看", doneTitle: "去处理");
544+
}
545+
if shouldOpenFile, let path = localPath {
546+
NSWorkspace.shared.open(path)
513547
}
514548
return successPath
515549
} else {
@@ -519,10 +553,21 @@ extension HomeController {
519553
} catch let error as HandleError {
520554
showAlert(title: "读取CSV文件失败 error:\(error.message)")
521555
} catch {
522-
showAlert(title: "读取CSV文件失败")
556+
showAlert(title: "读取CSV文件失败 error:\(error.localizedDescription)")
523557
}
524558
return []
525559
}
560+
func stringsText(_ fileModel: LanguageFileModel) -> String {
561+
let strings = fileModel.items.map { item in
562+
var text = ""
563+
if let desc = item.desc, !desc.isEmpty {
564+
text += "// \(desc)\n"
565+
}
566+
text += "\"\(Self.replaceSpecial(item.key))\" = \"\(Self.replaceSpecial(item.value))\""
567+
return text
568+
}
569+
return strings.joined(separator: "\n")
570+
}
526571
}
527572

528573
extension HomeController {
@@ -559,6 +604,12 @@ extension HomeController {
559604

560605
extension HomeController {
561606

607+
/// 展示弹窗
608+
/// - Parameters:
609+
/// - title: 标题
610+
/// - msg: 文本
611+
/// - doneTitle: 其他按钮标题,如果为 nil,则只展示取消按钮。
612+
/// - Returns: 返回是否选中了其他按钮。
562613
@discardableResult
563614
func showAlert(title:String, msg:String? = nil, doneTitle: String? = nil) -> Bool {
564615
let alert = NSAlert.init()

0 commit comments

Comments
 (0)