Skip to content

Commit d399bbb

Browse files
committed
feat: 自动插入项目基本逻辑。
1 parent 541a654 commit d399bbb

3 files changed

Lines changed: 188 additions & 117 deletions

File tree

Translator.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
94D9AA432D797227004501F5 /* 多语言翻译模板_数据正常.xlsx in Resources */ = {isa = PBXBuildFile; fileRef = 94D9AA412D797227004501F5 /* 多语言翻译模板_数据正常.xlsx */; };
2929
94D9AA462D797250004501F5 /* 多语言翻译模板_数据异常.csv in Resources */ = {isa = PBXBuildFile; fileRef = 94D9AA442D797250004501F5 /* 多语言翻译模板_数据异常.csv */; };
3030
94D9AA472D797250004501F5 /* 多语言翻译模板_数据正常.csv in Resources */ = {isa = PBXBuildFile; fileRef = 94D9AA452D797250004501F5 /* 多语言翻译模板_数据正常.csv */; };
31+
94E191062D797F1800EC4D65 /* UpdateStringsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94E191052D797F1800EC4D65 /* UpdateStringsHelper.swift */; };
3132
94F107302D534D5F00CF6631 /* FileKit in Frameworks */ = {isa = PBXBuildFile; productRef = 94F1072F2D534D5F00CF6631 /* FileKit */; };
3233
94F107322D534D6400CF6631 /* CSV in Frameworks */ = {isa = PBXBuildFile; productRef = 94F107312D534D6400CF6631 /* CSV */; };
3334
/* End PBXBuildFile section */
@@ -68,6 +69,7 @@
6869
94D9AA412D797227004501F5 /* 多语言翻译模板_数据正常.xlsx */ = {isa = PBXFileReference; lastKnownFileType = file; path = "多语言翻译模板_数据正常.xlsx"; sourceTree = "<group>"; };
6970
94D9AA442D797250004501F5 /* 多语言翻译模板_数据异常.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "多语言翻译模板_数据异常.csv"; sourceTree = "<group>"; };
7071
94D9AA452D797250004501F5 /* 多语言翻译模板_数据正常.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "多语言翻译模板_数据正常.csv"; sourceTree = "<group>"; };
72+
94E191052D797F1800EC4D65 /* UpdateStringsHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateStringsHelper.swift; sourceTree = "<group>"; };
7173
/* End PBXFileReference section */
7274

7375
/* Begin PBXFrameworksBuildPhase section */
@@ -113,6 +115,7 @@
113115
3C0B910622F2D91000F16E13 /* Translator */ = {
114116
isa = PBXGroup;
115117
children = (
118+
94E191042D797EFE00EC4D65 /* UpdateStringsHelper */,
116119
947CD8A92D70111200847AED /* CSVHelper */,
117120
3C6E342222F56CCD00403D4C /* Classes */,
118121
3C6E342822F56CCD00403D4C /* Resources */,
@@ -177,6 +180,14 @@
177180
path = TranslatorTests;
178181
sourceTree = "<group>";
179182
};
183+
94E191042D797EFE00EC4D65 /* UpdateStringsHelper */ = {
184+
isa = PBXGroup;
185+
children = (
186+
94E191052D797F1800EC4D65 /* UpdateStringsHelper.swift */,
187+
);
188+
path = UpdateStringsHelper;
189+
sourceTree = "<group>";
190+
};
180191
94F1072E2D534D5F00CF6631 /* Frameworks */ = {
181192
isa = PBXGroup;
182193
children = (
@@ -312,6 +323,7 @@
312323
3C6E343422F56CCE00403D4C /* String+Ext.swift in Sources */,
313324
94152F692D71BF840041F95A /* HandleError.swift in Sources */,
314325
3C6E343322F56CCE00403D4C /* HomeController.swift in Sources */,
326+
94E191062D797F1800EC4D65 /* UpdateStringsHelper.swift in Sources */,
315327
);
316328
runOnlyForDeploymentPostprocessing = 0;
317329
};

Translator/Classes/HomeController.swift

Lines changed: 80 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ private let localizableFileName = "Localizable.strings"
1414
private let keyTitles = ["key","Key","KEY"]
1515
private let keyBeiZhu = "备注"
1616

17+
private let stringsFileParentSuffix = ".lproj";
18+
1719
class HomeController: NSViewController {
1820

1921
@IBOutlet weak var savePathField: NSTextField!
@@ -34,6 +36,8 @@ class HomeController: NSViewController {
3436

3537
var localPath: URL?
3638
let csvHelper: CSVHelper = CSVHelper()
39+
/// 自动插入或者更新 strings
40+
let updateStringsHelper: UpdateStringsHelper = UpdateStringsHelper()
3741

3842
override func viewDidLoad() {
3943
super.viewDidLoad()
@@ -110,125 +114,31 @@ class HomeController: NSViewController {
110114
savePathField.stringValue = url.absoluteString.urlDecoded().removeFileHeader()
111115
}
112116
@IBAction func parseAutoInsertButtonTapped(_ sender: NSButton) {
113-
// 解析 excel 自动插入到对应语种的 strings 文件中
114-
do {
115-
let stringsFilePaths = try findPaths()
116-
117-
} catch let error as HandleError {
118-
showAlert(title: "自动导入异常",msg: error.message)
119-
} catch {
120-
117+
// 检查合法性
118+
let insertKey = self.insertKeyTextField.stringValue.removeWhitespace()
119+
guard !insertKey.isEmpty else {
120+
showAlert(title: "请填写插入key")
121+
return
121122
}
122-
}
123-
@IBAction func TestButtonTapped(_ sender: NSButton) {
124-
// 临时测试
125-
let path = "/Users/pandaeye/Documents/SupportFramwork/Translator/Translator/Resources/en.lproj/Test.strings"
126-
let key = "key4";
127123
guard let url = openPanel.url else {
128124
showAlert(title: Localized.failedToOpenFile)
129125
return
130126
}
127+
// 解析 excel 自动插入到对应语种的 strings 文件中
131128
do {
132-
let csvReader = try csvHelper.csvReader(url: url)
133-
let result = try csvHelper.parseCSVFile(reader: csvReader)
134-
if !result.errorInfo.isEmpty {
135-
Log.shared.error(result.errorInfo.writable.componentsJoined(by: "\n"))
136-
}
137-
if result.models.isEmpty {
138-
showAlert(title: "读取CSV成功,但未解析都符合数据")
139-
} else {
140-
// TODO: 匹配对应语种
141-
let isSuccess = insertOtherStrings(result.models.last!, to: path, after: key)
142-
}
129+
var stringsFilePaths = try findLanguagePaths()
130+
// 去掉 en.lproj
131+
stringsFilePaths.removeAll(where: {$0.fileName == "en\(stringsFileParentSuffix)"})
132+
// 开始对其他语言插入
133+
_ = self.autoInsertStrings(paths: stringsFilePaths, after: insertKey)
143134
} catch let error as HandleError {
144-
showAlert(title: "读取CSV文件失败 error:\(error.message)")
135+
showAlert(title: "自动导入异常",msg: error.message)
145136
} catch {
146-
showAlert(title: "读取CSV文件失败")
137+
147138
}
148-
149139
}
150-
func insertOtherStrings(_ stringsFileModel:LanguageFileModel, to filePath:String, after key:String) -> Bool {
151-
guard !stringsFileModel.items.isEmpty, !filePath.isEmpty, !key.isEmpty else {
152-
return false
153-
}
154-
// 插入指定位置
155-
guard let text = try? String(contentsOfFile: filePath, encoding: .utf8) else {
156-
Log.shared.error("自动插入,读取文件失败")
157-
return false
158-
}
159-
// 从路径读取 strings 文件并解析
160-
let result = LocalizableStringsParser.parse(string: text, locale: filePath)
161-
let filter = result.localizableStrings.filter { $0.key == key }
162-
guard filter.count == 1, let first = filter.first else {
163-
Log.shared.error("自动插入,找不到key,或者找到多个key, keyCount:\(filter.count)")
164-
return false
165-
}
166-
// 检查是否包含这个 key,
167-
var textHaveKey = false
168-
for item in stringsFileModel.items {
169-
let key = item.key
170-
let filterKey = result.localizableStrings.filter { temp in
171-
temp.key == key
172-
}
173-
if filterKey.isEmpty {
174-
textHaveKey = true
175-
}
176-
}
177-
if (textHaveKey) {
178-
Log.shared.error("自动插入,将要插入的文件已经包含该 相同的key \(stringsFileModel.items)")
179-
return false
180-
}
181-
// 找到原来strings 匹配的 的key value 组合值, 必须要按照这个格式才能匹配。
182-
let subStr = "\"\(first.key)\" = \"\(first.value)\";"
183-
// 找到插入位置
184-
185-
if #available(macOS 13.0, *) {
186-
do {
187-
let indexResult = try LocalizableStringsUtils.findInsertIndex(allStrings:text , subStr: subStr)
188-
// 替换到指定位置之后 \n + 需要插入的内容。
189-
guard let index = indexResult.index else {
190-
Log.shared.error("自动插入,找不到插入点")
191-
return false
192-
}
193-
let insertIndexHave2EmptyLine = indexResult.insertIndexHave2EmptyLine
194-
var willInsertText = "\n"
195-
for item in stringsFileModel.items {
196-
if let desc = item.desc, !desc.isEmpty {
197-
willInsertText += "\n// \(desc)"
198-
}
199-
willInsertText += "\n\"\(item.key)\" = \"\(item.value)\";"
200-
}
201-
if !insertIndexHave2EmptyLine {
202-
willInsertText = willInsertText + "\n\n"
203-
}
204-
var allStrings = text
205-
allStrings.insert(contentsOf: willInsertText, at: index)
206-
// 删除文件,重新写入
207-
do {
208-
try FileManager.default.removeItem(atPath: filePath)
209-
try allStrings.write(toFile: filePath, atomically: true, encoding: .utf8)
210-
return true
211-
} catch let error {
212-
Log.shared.error("自动插入,文件删除或者写入失败:\(error)")
213-
return false
214-
}
215-
} catch let error as LocalizableStringsFindInsertIndexError {
216-
switch error {
217-
case .multipleMatches:
218-
Log.shared.error("自动插入,匹配到多个,无法自动插入 subxStr:\(subStr)")
219-
case .noMatch:
220-
Log.shared.error("自动插入,找不到匹配项,无法自动插入 subxStr:\(subStr)")
221-
case .multiLineComment:
222-
Log.shared.error("自动插入,插入点后存在多行注释\\* \n */,无法自动插入 subxStr:\(subStr)")
223-
}
224-
return false
225-
} catch {
226-
return false
227-
}
228-
} else {
229-
Log.shared.error("自动插入,macOS 版本不支持, 应该大于 13.0")
230-
return false
231-
}
140+
@IBAction func TestButtonTapped(_ sender: NSButton) {
141+
// 测试
232142
}
233143

234144
/// MARK: - Lazy
@@ -413,7 +323,7 @@ extension HomeController {
413323
}
414324

415325
}
416-
// MARK: 额外增加方法
326+
// MARK: 额外增加方法 (等待删除部分方法)
417327
extension HomeController {
418328
/// 是否是备注列
419329
func isDescrTitle(_ title: String) -> Bool {
@@ -534,32 +444,85 @@ extension HomeController {
534444
}
535445
// 自动插入
536446
extension HomeController {
537-
func findPaths() throws -> [Path] {
447+
func findLanguagePaths() throws -> [Path] {
538448
let projectPath = projectTextField.stringValue.trimmingCharacters(in: .whitespaces)
539449
let stringsFileName = stringsFileNameTextField.stringValue.trimmingCharacters(in: .whitespaces)
540450
let path = Path(projectPath)
451+
452+
if projectPath.isEmpty || !path.exists {
453+
throw HandleError(message: "路径不能为空,或者不存在,请检查多语言目录地址");
454+
}
541455
let stringsFilePaths = path.children().compactMap { item in
542-
if item.fileName.contains(".lproj") { // 判断是否是 lproj 文件夹
456+
if item.fileName.contains(stringsFileParentSuffix) { // 判断是否是 lproj 文件夹, 但是要除开 en,
543457
let filterFiles = item.children().filter { path in
544458
// 不是目录,且包含指定问价名
545-
!path.isDirectoryFile && path.fileName.contains(stringsFileName);
459+
!path.isDirectoryFile && path.fileName.contains(stringsFileName)
546460
}
547461
return filterFiles.first
548462
} else {
549463
return nil
550464
}
551465
}
552-
if projectPath.isEmpty {
553-
throw HandleError(message: "路径不能为空");
554-
}
555466
if stringsFileName.isEmpty {
556467
throw HandleError(message: "strings文件名不能为空");
557468
}
558469
if stringsFilePaths.isEmpty {
559-
throw HandleError(message: "找不目标文件");
470+
throw HandleError(message: "找不xx.lproj目标文件");
560471
}
561472
return stringsFilePaths
562473
}
474+
/// 自动插入翻译到 strings 文件,返回的是插入成功的。
475+
func autoInsertStrings(paths:[Path], after key:String ) -> [Path] {
476+
guard let url = openPanel.url else {
477+
showAlert(title: Localized.failedToOpenFile)
478+
return []
479+
}
480+
do {
481+
let csvReader = try csvHelper.csvReader(url: url)
482+
let result = try csvHelper.parseCSVFile(reader: csvReader)
483+
if !result.errorInfo.isEmpty {
484+
Log.shared.error(result.errorInfo.writable.componentsJoined(by: "\n"))
485+
}
486+
if result.models.isEmpty {
487+
showAlert(title: "读取CSV成功,但未解析都符合数据")
488+
} else {
489+
if #available(macOS 13.0, *) {
490+
var successPath:[Path] = []
491+
var errorMsg = "自动解析插入失败\n"
492+
// 真正插入
493+
for path in paths {
494+
let languageName = path.fileNameWithoutExtension
495+
if let aimFileModel = result.models.first(where: {$0.languageName.lowercased() == languageName.lowercased()}) {
496+
if let error = updateStringsHelper.insertOtherStrings(result.models.last!, to: path.rawValue, after: key) {
497+
errorMsg += error.message + "\n"
498+
} else {
499+
successPath.append(path)
500+
}
501+
} else {
502+
// 没有找到对应多语言列
503+
errorMsg += "在csv 中没有找到对应语种\(languageName)翻译\n"
504+
}
505+
}
506+
if successPath.isEmpty {
507+
showAlert(title: "所有多语言插入失败,手动处理", msg: errorMsg, doneTitle: "确定")
508+
} else if successPath.count == paths.count {
509+
// 所有都成功
510+
showAlert(title: "所有多语言插入成功", doneTitle: "确定")
511+
} else {
512+
showAlert(title: "部分多语言插入成功,手动处理", msg: errorMsg, doneTitle: "确定");
513+
}
514+
return successPath
515+
} else {
516+
showAlert(title: "系统版本应该大于 macOS 13.0")
517+
}
518+
}
519+
} catch let error as HandleError {
520+
showAlert(title: "读取CSV文件失败 error:\(error.message)")
521+
} catch {
522+
showAlert(title: "读取CSV文件失败")
523+
}
524+
return []
525+
}
563526
}
564527

565528
extension HomeController {

0 commit comments

Comments
 (0)