diff --git a/DataCompiler/dataCompiler.swift b/DataCompiler/dataCompiler.swift index f4dfd21e..a20e0695 100644 --- a/DataCompiler/dataCompiler.swift +++ b/DataCompiler/dataCompiler.swift @@ -60,9 +60,9 @@ extension String { // MARK: - 引入小數點位數控制函式 // Ref: https://stackoverflow.com/a/32581409/4162914 -extension Float { - fileprivate func rounded(toPlaces places: Int) -> Float { - let divisor = pow(10.0, Float(places)) +extension Double { + fileprivate func rounded(toPlaces places: Int) -> Double { + let divisor = pow(10.0, Double(places)) return (self * divisor).rounded() / divisor } } @@ -81,17 +81,16 @@ func ** (_ base: Double, _ exp: Double) -> Double { pow(base, exp) } -func ** (_ base: Float, _ exp: Float) -> Float { - pow(base, exp) -} - // MARK: - 定義檔案結構 -struct Entry { - var valPhone: String = "" - var valPhrase: String = "" - var valWeight: Float = -1.0 - var valCount: Int = 0 +struct Unigram: CustomStringConvertible { + var key: String = "" + var value: String = "" + var score: Double = -1.0 + var count: Int = 0 + var description: String { + "(\(key), \(value), \(score))" + } } // MARK: - 注音加密,減少 plist 體積 @@ -105,8 +104,8 @@ func cnvPhonabetToASCII(_ incoming: String) -> String { ] var strOutput = incoming if !strOutput.contains("_") { - for entry in dicPhonabet2ASCII { - strOutput = strOutput.replacingOccurrences(of: entry.key, with: entry.value) + for Unigram in dicPhonabet2ASCII { + strOutput = strOutput.replacingOccurrences(of: Unigram.key, with: Unigram.value) } } return strOutput @@ -146,8 +145,8 @@ private let urlPlistCHT: String = "./data-cht.plist" // MARK: - 載入詞組檔案且輸出陣列 -func rawDictForPhrases(isCHS: Bool) -> [Entry] { - var arrEntryRAW: [Entry] = [] +func rawDictForPhrases(isCHS: Bool) -> [Unigram] { + var arrUnigramRAW: [Unigram] = [] var strRAW = "" let urlCustom: String = isCHS ? urlCHSforCustom : urlCHTforCustom let urlTABE: String = isCHS ? urlCHSforTABE : urlCHTforTABE @@ -195,7 +194,7 @@ func rawDictForPhrases(isCHS: Bool) -> [Entry] { varLineDataProcessed += currentCell } } - // 然後直接乾脆就轉成 Entry 吧。 + // 然後直接乾脆就轉成 Unigram 吧。 let arrCells: [String] = varLineDataProcessed.components(separatedBy: "\t") count = 0 // 不需要再定義,因為之前已經有定義過了。 var phone = "" @@ -211,22 +210,22 @@ func rawDictForPhrases(isCHS: Bool) -> [Entry] { } } if phrase != "" { // 廢掉空數據;之後無須再這樣處理。 - arrEntryRAW += [ - Entry( - valPhone: phone, valPhrase: phrase, valWeight: 0.0, - valCount: occurrence + arrUnigramRAW += [ + Unigram( + key: phone, value: phrase, score: 0.0, + count: occurrence ) ] } } NSLog(" - \(i18n): 成功生成詞語語料辭典(權重待計算)。") - return arrEntryRAW + return arrUnigramRAW } // MARK: - 載入單字檔案且輸出陣列 -func rawDictForKanjis(isCHS: Bool) -> [Entry] { - var arrEntryRAW: [Entry] = [] +func rawDictForKanjis(isCHS: Bool) -> [Unigram] { + var arrUnigramRAW: [Unigram] = [] var strRAW = "" let i18n: String = isCHS ? "簡體中文" : "繁體中文" // 讀取內容 @@ -272,7 +271,7 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { varLineDataProcessed += currentCell } } - // 然後直接乾脆就轉成 Entry 吧。 + // 然後直接乾脆就轉成 Unigram 吧。 let arrCells: [String] = varLineDataProcessed.components(separatedBy: "\t") count = 0 // 不需要再定義,因為之前已經有定義過了。 var phone = "" @@ -288,22 +287,22 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { } } if phrase != "" { // 廢掉空數據;之後無須再這樣處理。 - arrEntryRAW += [ - Entry( - valPhone: phone, valPhrase: phrase, valWeight: 0.0, - valCount: occurrence + arrUnigramRAW += [ + Unigram( + key: phone, value: phrase, score: 0.0, + count: occurrence ) ] } } NSLog(" - \(i18n): 成功生成單字語料辭典(權重待計算)。") - return arrEntryRAW + return arrUnigramRAW } // MARK: - 載入非漢字檔案且輸出陣列 -func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { - var arrEntryRAW: [Entry] = [] +func rawDictForNonKanjis(isCHS: Bool) -> [Unigram] { + var arrUnigramRAW: [Unigram] = [] var strRAW = "" let i18n: String = isCHS ? "簡體中文" : "繁體中文" // 讀取內容 @@ -347,7 +346,7 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { varLineDataProcessed += currentCell } } - // 然後直接乾脆就轉成 Entry 吧。 + // 然後直接乾脆就轉成 Unigram 吧。 let arrCells: [String] = varLineDataProcessed.components(separatedBy: "\t") count = 0 // 不需要再定義,因為之前已經有定義過了。 var phone = "" @@ -363,60 +362,60 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { } } if phrase != "" { // 廢掉空數據;之後無須再這樣處理。 - arrEntryRAW += [ - Entry( - valPhone: phone, valPhrase: phrase, valWeight: 0.0, - valCount: occurrence + arrUnigramRAW += [ + Unigram( + key: phone, value: phrase, score: 0.0, + count: occurrence ) ] } } NSLog(" - \(i18n): 成功生成非漢字語料辭典(權重待計算)。") - return arrEntryRAW + return arrUnigramRAW } -func weightAndSort(_ arrStructUncalculated: [Entry], isCHS: Bool) -> [Entry] { +func weightAndSort(_ arrStructUncalculated: [Unigram], isCHS: Bool) -> [Unigram] { let i18n: String = isCHS ? "簡體中文" : "繁體中文" - var arrStructCalculated: [Entry] = [] - let fscale: Float = 2.7 - var norm: Float = 0.0 - for entry in arrStructUncalculated { - if entry.valCount >= 0 { - norm += fscale ** (Float(entry.valPhrase.count) / 3.0 - 1.0) - * Float(entry.valCount) + var arrStructCalculated: [Unigram] = [] + let fscale = 2.7 + var norm = 0.0 + for unigram in arrStructUncalculated { + if unigram.count >= 0 { + norm += fscale ** (Double(unigram.value.count) / 3.0 - 1.0) + * Double(unigram.count) } } // norm 計算完畢,開始將 norm 作為新的固定常數來為每個詞條記錄計算權重。 // 將新酷音的詞語出現次數數據轉換成小麥引擎可讀的數據形式。 // 對出現次數小於 1 的詞條,將 0 當成 0.5 來處理、以防止除零。 - for entry in arrStructUncalculated { - var weight: Float = 0 - switch entry.valCount { + for unigram in arrStructUncalculated { + var weight: Double = 0 + switch unigram.count { case -2: // 拗音假名 weight = -13 case -1: // 單個假名 weight = -13 case 0: // 墊底低頻漢字與詞語 weight = log10( - fscale ** (Float(entry.valPhrase.count) / 3.0 - 1.0) * 0.25 / norm) + fscale ** (Double(unigram.value.count) / 3.0 - 1.0) * 0.25 / norm) default: weight = log10( - fscale ** (Float(entry.valPhrase.count) / 3.0 - 1.0) - * Float(entry.valCount) / norm) // Credit: MJHsieh. + fscale ** (Double(unigram.value.count) / 3.0 - 1.0) + * Double(unigram.count) / norm) // Credit: MJHsieh. } - let weightRounded: Float = weight.rounded(toPlaces: 3) // 為了節省生成的檔案體積,僅保留小數點後三位。 + let weightRounded: Double = weight.rounded(toPlaces: 3) // 為了節省生成的檔案體積,僅保留小數點後三位。 arrStructCalculated += [ - Entry( - valPhone: entry.valPhone, valPhrase: entry.valPhrase, valWeight: weightRounded, - valCount: entry.valCount + Unigram( + key: unigram.key, value: unigram.value, score: weightRounded, + count: unigram.count ) ] } NSLog(" - \(i18n): 成功計算權重。") // ========================================== // 接下來是排序,先按照注音遞減排序一遍、再按照權重遞減排序一遍。 - let arrStructSorted: [Entry] = arrStructCalculated.sorted(by: { lhs, rhs -> Bool in - (lhs.valPhone, rhs.valCount) < (rhs.valPhone, lhs.valCount) + let arrStructSorted: [Unigram] = arrStructCalculated.sorted(by: { lhs, rhs -> Bool in + (lhs.key, rhs.count) < (rhs.key, lhs.count) }) NSLog(" - \(i18n): 排序整理完畢,準備編譯要寫入的檔案內容。") return arrStructSorted @@ -434,9 +433,11 @@ func fileOutput(isCHS: Bool) { // 讀取標點內容 do { strPunctuation = try String(contentsOfFile: urlPunctuation, encoding: .utf8).replacingOccurrences( - of: "\t", with: " ") + of: "\t", with: " " + ) strPrintLine += try String(contentsOfFile: urlPunctuation, encoding: .utf8).replacingOccurrences( - of: "\t", with: " ") + of: "\t", with: " " + ) } catch { NSLog(" - \(i18n): Exception happened when reading raw punctuation data.") } @@ -453,18 +454,33 @@ func fileOutput(isCHS: Bool) { } } } - var arrStructUnified: [Entry] = [] + var arrStructUnified: [Unigram] = [] arrStructUnified += rawDictForKanjis(isCHS: isCHS) arrStructUnified += rawDictForNonKanjis(isCHS: isCHS) arrStructUnified += rawDictForPhrases(isCHS: isCHS) // 計算權重且排序 arrStructUnified = weightAndSort(arrStructUnified, isCHS: isCHS) - for entry in arrStructUnified { - let theKey = entry.valPhone - let theValue = (String(entry.valWeight) + " " + entry.valPhrase) + + // 資料重複性檢查 + NSLog(" - \(i18n): 執行資料重複性檢查,會在之後再給出對應的檢查結果。") + var setAlreadyInserted = Set() + var arrFoundedDuplications = [String]() + + // 健康狀況檢查 + NSLog(" - \(i18n): 執行資料健康狀況檢查。") + print(healthCheck(arrStructUnified)) + for unigram in arrStructUnified { + if setAlreadyInserted.contains(unigram.value + "\t" + unigram.key) { + arrFoundedDuplications.append(unigram.value + "\t" + unigram.key) + } else { + setAlreadyInserted.insert(unigram.value + "\t" + unigram.key) + } + + let theKey = unigram.key + let theValue = (String(unigram.score) + " " + unigram.value) rangeMap[cnvPhonabetToASCII(theKey), default: []].append(theValue.data(using: .utf8)!) strPrintLine += - entry.valPhone + " " + entry.valPhrase + " " + String(entry.valWeight) + unigram.key + " " + unigram.value + " " + String(unigram.score) + "\n" } NSLog(" - \(i18n): 要寫入檔案的 txt 內容編譯完畢。") @@ -476,6 +492,12 @@ func fileOutput(isCHS: Bool) { NSLog(" - \(i18n): Error on writing strings to file: \(error)") } NSLog(" - \(i18n): 寫入完成。") + if !arrFoundedDuplications.isEmpty { + NSLog(" - \(i18n): 尋得下述重複項目,請務必手動排查:") + print("-------------------") + print(arrFoundedDuplications.joined(separator: "\n")) + } + print("===================") } func commonFileOutput() { @@ -555,3 +577,268 @@ func main() { } main() + +// MARK: - 辭庫健康狀況檢查專用函式 + +func healthCheck(_ data: [Unigram]) -> String { + var result = "" + var unigramMonoChar = [String: Unigram]() + var valueToScore = [String: Double]() + let unigramMonoCharCounter = data.filter { $0.score > -14 && $0.key.split(separator: "-").count == 1 }.count + let unigramPolyCharCounter = data.filter { $0.score > -14 && $0.key.split(separator: "-").count > 1 }.count + + // 核心字詞庫的內容頻率一般大於 -10,但也得考慮某些包含假名的合成詞。 + for neta in data.filter({ $0.score > -14 }) { + valueToScore[neta.value] = max(neta.score, valueToScore[neta.value] ?? -14) + let theKeySliceArr = neta.key.split(separator: "-") + guard let theKey = theKeySliceArr.first, theKeySliceArr.count == 1 else { continue } + if unigramMonoChar.keys.contains(String(theKey)), let theRecord = unigramMonoChar[String(theKey)] { + if neta.score > theRecord.score { unigramMonoChar[String(theKey)] = neta } + } else { + unigramMonoChar[String(theKey)] = neta + } + } + + var faulty = [Unigram]() + var indifferents: [(String, String, Double, [Unigram], Double)] = [] + var insufficients: [(String, String, Double, [Unigram], Double)] = [] + var competingUnigrams = [(String, Double, String, Double)]() + + for neta in data.filter({ $0.key.split(separator: "-").count >= 2 && $0.score > -14 }) { + var competants = [Unigram]() + var tscore: Double = 0 + var bad = false + for x in neta.key.split(separator: "-") { + if !unigramMonoChar.keys.contains(String(x)) { + bad = true + break + } + guard let u = unigramMonoChar[String(x)] else { continue } + tscore += u.score + competants.append(u) + } + if bad { + faulty.append(neta) + continue + } + if tscore >= neta.score { + let instance = (neta.key, neta.value, neta.score, competants, neta.score - tscore) + let valueJoined = String(competants.map(\.value).joined(separator: "")) + if neta.value == valueJoined { + indifferents.append(instance) + } else { + if valueToScore.keys.contains(valueJoined), neta.value != valueJoined { + if let valueJoinedScore = valueToScore[valueJoined], neta.score < valueJoinedScore { + competingUnigrams.append((neta.value, neta.score, valueJoined, valueJoinedScore)) + } + } + insufficients.append(instance) + } + } + } + + insufficients = insufficients.sorted(by: { lhs, rhs -> Bool in + (lhs.2) > (rhs.2) + }) + competingUnigrams = competingUnigrams.sorted(by: { lhs, rhs -> Bool in + (lhs.1 - lhs.3) > (rhs.1 - rhs.3) + }) + + let separator: String = { + var result = "" + for _ in 0..<72 { result += "-" } + return result + }() + + func printl(_ input: String) { + result += input + "\n" + } + + printl(separator) + printl("持單個字符的有效單元圖數量:\(unigramMonoCharCounter)") + printl("持多個字符的有效單元圖數量:\(unigramPolyCharCounter)") + + printl(separator) + printl("總結一下那些容易被單個漢字的字頻干擾輸入的詞組單元圖:") + printl("因干擾組件和字詞本身完全重疊、而不需要處理的單元圖的數量:\(indifferents.count)") + printl( + "有 \(insufficients.count) 個複字單元圖被自身成分讀音對應的其它單字單元圖奪權,約佔全部有效單元圖的 \(insufficients.count / unigramPolyCharCounter * 100)%," + ) + printl("\n其中有:") + + var insufficientsMap = [Int: [(String, String, Double, [Unigram], Double)]]() + for x in 2...10 { + insufficientsMap[x] = insufficients.filter { $0.0.split(separator: "-").count == x } + } + + printl(" \(insufficientsMap[2]?.count ?? 0) 個有效雙字單元圖") + printl(" \(insufficientsMap[3]?.count ?? 0) 個有效三字單元圖") + printl(" \(insufficientsMap[4]?.count ?? 0) 個有效四字單元圖") + printl(" \(insufficientsMap[5]?.count ?? 0) 個有效五字單元圖") + printl(" \(insufficientsMap[6]?.count ?? 0) 個有效六字單元圖") + printl(" \(insufficientsMap[7]?.count ?? 0) 個有效七字單元圖") + printl(" \(insufficientsMap[8]?.count ?? 0) 個有效八字單元圖") + printl(" \(insufficientsMap[9]?.count ?? 0) 個有效九字單元圖") + printl(" \(insufficientsMap[10]?.count ?? 0) 個有效十字單元圖") + + if let insufficientsMap2 = insufficientsMap[2], !insufficientsMap2.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效雙字單元圖") + for (i, content) in insufficientsMap2.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap3 = insufficientsMap[3], !insufficientsMap3.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效三字單元圖") + for (i, content) in insufficientsMap3.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap4 = insufficientsMap[4], !insufficientsMap4.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效四字單元圖") + for (i, content) in insufficientsMap4.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap5 = insufficientsMap[5], !insufficientsMap5.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效五字單元圖") + for (i, content) in insufficientsMap5.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap6 = insufficientsMap[6], !insufficientsMap6.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效六字單元圖") + for (i, content) in insufficientsMap6.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap7 = insufficientsMap[7], !insufficientsMap7.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效七字單元圖") + for (i, content) in insufficientsMap7.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap8 = insufficientsMap[8], !insufficientsMap8.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效八字單元圖") + for (i, content) in insufficientsMap8.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap9 = insufficientsMap[9], !insufficientsMap9.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效九字單元圖") + for (i, content) in insufficientsMap9.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if let insufficientsMap10 = insufficientsMap[10], !insufficientsMap10.isEmpty { + printl(separator) + printl("前二十五個被奪權的有效十字單元圖") + for (i, content) in insufficientsMap10.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += content.1 + "," + contentToPrint += String(content.2) + "," + contentToPrint += "[" + content.3.map(\.description).joined(separator: ",") + "]" + "," + contentToPrint += String(content.4) + "}" + printl(contentToPrint) + } + } + + if !competingUnigrams.isEmpty { + printl(separator) + printl("也發現有 \(competingUnigrams.count) 個複字單元圖被某些由高頻單字組成的複字單元圖奪權的情況,") + printl("例如(前二十五例):") + for (i, content) in competingUnigrams.enumerated() { + if i == 25 { break } + var contentToPrint = "{" + contentToPrint += content.0 + "," + contentToPrint += String(content.1) + "," + contentToPrint += content.2 + "," + contentToPrint += String(content.3) + "}" + printl(contentToPrint) + } + } + + if !faulty.isEmpty { + printl(separator) + printl("下述單元圖用到了漢字核心表當中尚未收錄的讀音,可能無法正常輸入:") + for content in faulty { + printl(content.description) + } + } + + result += "\n" + return result +} diff --git a/Installer/InstallerBg.png b/Installer/InstallerBg.png index e2fa4405..5f9229cd 100644 Binary files a/Installer/InstallerBg.png and b/Installer/InstallerBg.png differ diff --git a/Installer/InstallerBg@2x.png b/Installer/InstallerBg@2x.png index 0246541e..8fbb3a6f 100644 Binary files a/Installer/InstallerBg@2x.png and b/Installer/InstallerBg@2x.png differ diff --git a/README-CHT.md b/README-CHT.md index 0c36a3b7..e28c6ea3 100644 --- a/README-CHT.md +++ b/README-CHT.md @@ -114,7 +114,7 @@ ## 參與研發時的注意事項 -歡迎參與威注音的研發。論及相關細則,請洽請洽該倉庫內的「[CONTRIBUTING.md](./CONTRIBUTING.md)」檔案、以及《[常見問題解答](./FAQ.md)》。 +歡迎參與威注音的研發。論及相關細則,請洽該倉庫內的「[CONTRIBUTING.md](./CONTRIBUTING.md)」檔案、以及《[常見問題解答](./FAQ.md)》。 敝專案採用了《[貢獻者品行準則承約書 v2.1](./code-of-conduct.md)》。考慮到上游鏈接給出的中文版翻譯與英文原文嚴重不符合的情況(會出現因執法與被執法雙方的認知偏差導致的矛盾,非常容易變成敵我矛盾),敝專案使用了自行翻譯的版本、且新增了一些能促進雙方共識的註解。 diff --git a/README.md b/README.md index 9682c00a..89301d51 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ ## 参与研发时的注意事项 -欢迎参与威注音的研发。论及相关细则,请洽请洽该仓库内的「[CONTRIBUTING.md](./CONTRIBUTING.md)」档案、以及《[常见问题解答](./FAQ.md)》。 +欢迎参与威注音的研发。论及相关细则,请洽该仓库内的「[CONTRIBUTING.md](./CONTRIBUTING.md)」档案、以及《[常见问题解答](./FAQ.md)》。 敝专案采用了《[贡献者品行准则承约书 v2.1](./code-of-conduct.md)》。考虑到上游链接给出的中文版翻译与英文原文严重不符合的情况(会出现因执法与被执法双方的认知偏差导致的矛盾,非常容易变成敌我矛盾),敝专案使用了自行翻译的版本、且新增了一些能促进双方共识的注解。 diff --git a/Source/Data b/Source/Data index 50250d97..345b21db 160000 --- a/Source/Data +++ b/Source/Data @@ -1 +1 @@ -Subproject commit 50250d970a3481ec7653a71120413708a76224d8 +Subproject commit 345b21db6510caf63184716178837c5563e68123 diff --git a/Source/Modules/ControllerModules/KeyHandler_Core.swift b/Source/Modules/ControllerModules/KeyHandler_Core.swift index 93217d84..4caf14b5 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Core.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Core.swift @@ -149,10 +149,10 @@ class KeyHandler { /// - Parameter key: 給定的聯想詞的開頭字。 /// - Returns: 抓取到的聯想詞陣列。 /// 不會是 nil,但那些負責接收結果的函式會對空白陣列結果做出正確的處理。 - func buildAssociatePhraseArray(withKey key: String) -> [(String, String)] { + func buildAssociatePhraseArray(withPair pair: Megrez.KeyValuePaired) -> [(String, String)] { var arrResult: [(String, String)] = [] - if currentLM.hasAssociatedPhrasesFor(key: key) { - arrResult = currentLM.associatedPhrasesFor(key: key).map { ("", $0) } + if currentLM.hasAssociatedPhrasesFor(pair: pair) { + arrResult = currentLM.associatedPhrasesFor(pair: pair).map { ("", $0) } } return arrResult } diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index b3544270..f9bb3236 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -78,11 +78,6 @@ extension KeyHandler { // MARK: Enter if input.isEnter { - if state is InputState.AssociatedPhrases { - clear() - stateCallback(InputState.EmptyIgnoringPreviousState()) - return true - } delegate!.keyHandler( self, didSelectCandidateAt: ctlCandidateCurrent.selectedCandidateIndex, diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index b984167d..db5a6e62 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -225,6 +225,7 @@ extension KeyHandler { ) if choosingCandidates.candidates.count == 1 { clear() + let reading: String = choosingCandidates.candidates.first?.0 ?? "" let text: String = choosingCandidates.candidates.first?.1 ?? "" stateCallback(InputState.Committing(textToCommit: text)) @@ -233,7 +234,7 @@ extension KeyHandler { } else { if let associatedPhrases = buildAssociatePhraseState( - withKey: text, + withPair: .init(key: reading, value: text), isTypingVertical: input.isTypingVertical ), !associatedPhrases.candidates.isEmpty { @@ -261,7 +262,7 @@ extension KeyHandler { // MARK: 用上下左右鍵呼叫選字窗 (Calling candidate window using Up / Down or PageUp / PageDn.) - if let currentState = state as? InputState.NotEmpty, composer.isEmpty, + if let currentState = state as? InputState.NotEmpty, composer.isEmpty, !input.isOptionHold, input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace || input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior) || (input.isTypingVertical && (input.isVerticalTypingOnlyChooseCandidateKey)) @@ -353,6 +354,17 @@ extension KeyHandler { // MARK: AbsorbedArrowKey if input.isAbsorbedArrowKey || input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse { + if input.isOptionHold, state.type == .ofInputting { + if input.isExtraChooseCandidateKey { + return handleInlineCandidateRotation( + state: state, reverseModifier: false, stateCallback: stateCallback, errorCallback: errorCallback + ) + } else if input.isExtraChooseCandidateKeyReverse { + return handleInlineCandidateRotation( + state: state, reverseModifier: true, stateCallback: stateCallback, errorCallback: errorCallback + ) + } + } return handleAbsorbedArrowKey(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index 40e2a73d..bc45cb13 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -198,12 +198,12 @@ extension KeyHandler { /// - isTypingVertical: 是否縱排輸入? /// - Returns: 回呼一個新的聯想詞狀態,來就給定的聯想詞陣列資料內容顯示選字窗。 func buildAssociatePhraseState( - withKey key: String!, + withPair pair: Megrez.KeyValuePaired, isTypingVertical: Bool ) -> InputState.AssociatedPhrases! { // 上一行必須要用驚嘆號,否則 Xcode 會誤導你砍掉某些實際上必需的語句。 InputState.AssociatedPhrases( - candidates: buildAssociatePhraseArray(withKey: key), isTypingVertical: isTypingVertical + candidates: buildAssociatePhraseArray(withPair: pair), isTypingVertical: isTypingVertical ) } diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift b/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift index 7b0f6f92..d3f60594 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift @@ -122,7 +122,8 @@ extension ctlInputMethod: ctlCandidateDelegate { handle(state: InputState.Committing(textToCommit: composingBuffer)) if mgrPrefs.associatedPhrasesEnabled, let associatePhrases = keyHandler.buildAssociatePhraseState( - withKey: composingBuffer, isTypingVertical: state.isTypingVertical + withPair: .init(key: selectedValue.0, value: selectedValue.1), + isTypingVertical: state.isTypingVertical ), !associatePhrases.candidates.isEmpty { handle(state: associatePhrases) @@ -140,7 +141,8 @@ extension ctlInputMethod: ctlCandidateDelegate { handle(state: InputState.Committing(textToCommit: selectedValue.1)) if mgrPrefs.associatedPhrasesEnabled, let associatePhrases = keyHandler.buildAssociatePhraseState( - withKey: selectedValue.1, isTypingVertical: state.isTypingVertical + withPair: .init(key: selectedValue.0, value: selectedValue.1), + isTypingVertical: state.isTypingVertical ), !associatePhrases.candidates.isEmpty { handle(state: associatePhrases) diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift b/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift index 3c1727e1..ff852107 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Menu.swift @@ -117,15 +117,18 @@ extension ctlInputMethod { action: #selector(openExcludedPhrases(_:)), keyEquivalent: "" ) + if optionKeyPressed || mgrPrefs.associatedPhrasesEnabled { + menu.addItem( + withTitle: NSLocalizedString("Edit Associated Phrases…", comment: ""), + action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "" + ) + } + if optionKeyPressed { menu.addItem( withTitle: NSLocalizedString("Edit Phrase Replacement Table…", comment: ""), action: #selector(openPhraseReplacement(_:)), keyEquivalent: "" ) - menu.addItem( - withTitle: NSLocalizedString("Edit Associated Phrases…", comment: ""), - action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "" - ) menu.addItem( withTitle: NSLocalizedString("Edit User Symbol & Emoji Data…", comment: ""), action: #selector(openUserSymbols(_:)), keyEquivalent: "" @@ -139,6 +142,8 @@ extension ctlInputMethod { ) } + menu.addItem(NSMenuItem.separator()) // --------------------- + menu.addItem( withTitle: NSLocalizedString("Optimize Memorized Phrases", comment: ""), action: #selector(removeUnigramsFromUOM(_:)), keyEquivalent: "" diff --git a/Source/Modules/IMEModules/IME.swift b/Source/Modules/IMEModules/IME.swift index cd9a72e1..45b5f1bb 100644 --- a/Source/Modules/IMEModules/IME.swift +++ b/Source/Modules/IMEModules/IME.swift @@ -88,6 +88,8 @@ public enum IME { // MARK: - Initializing Language Models. static func initLangModels(userOnly: Bool) { + mgrLangModel.chkUserLMFilesExist(.imeModeCHT) + mgrLangModel.chkUserLMFilesExist(.imeModeCHS) // mgrLangModel 的 loadUserPhrases 等函式在自動讀取 dataFolderPath 時, // 如果發現自訂目錄不可用,則會自動抹去自訂目錄設定、改採預設目錄。 // 所以這裡不需要特別處理。 diff --git a/Source/Modules/LangModelRelated/LMInstantiator.swift b/Source/Modules/LangModelRelated/LMInstantiator.swift index 69b9c73f..96e2bf07 100644 --- a/Source/Modules/LangModelRelated/LMInstantiator.swift +++ b/Source/Modules/LangModelRelated/LMInstantiator.swift @@ -82,7 +82,7 @@ extension vChewing { // 聲明使用者語言模組。 // 使用者語言模組使用多執行緒的話,可能會導致一些問題。有時間再仔細排查看看。 var lmUserPhrases = LMCoreEX( - reverse: true, consolidate: true, defaultScore: 0, forceDefaultScore: true + reverse: true, consolidate: true, defaultScore: 0, forceDefaultScore: false ) var lmFiltered = LMCoreEX( reverse: true, consolidate: true, defaultScore: 0, forceDefaultScore: true @@ -249,13 +249,21 @@ extension vChewing { } public func associatedPhrasesFor(key: String) -> [String] { - lmAssociates.valuesFor(key: key) ?? [] + lmAssociates.valuesFor(key: key) } public func hasAssociatedPhrasesFor(key: String) -> Bool { lmAssociates.hasValuesFor(key: key) } + public func associatedPhrasesFor(pair: Megrez.KeyValuePaired) -> [String] { + lmAssociates.valuesFor(pair: pair) + } + + public func hasAssociatedPhrasesFor(pair: Megrez.KeyValuePaired) -> Bool { + lmAssociates.hasValuesFor(pair: pair) + } + /// 該函式不起作用,僅用來滿足 LangModelProtocol 協定的要求。 public func bigramsFor(precedingKey _: String, key _: String) -> [Megrez.Bigram] { .init() } diff --git a/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift b/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift index 2740e293..a17d1faf 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift @@ -27,7 +27,7 @@ import Foundation extension vChewing { @frozen public struct LMAssociates { - var rangeMap: [String: [Range]] = [:] + var rangeMap: [String: [(Range, Int)]] = [:] var strData: String = "" public var count: Int { @@ -52,13 +52,16 @@ extension vChewing { do { strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ") - strData.ranges(splitBy: "\n").forEach { + strData = strData.replacingOccurrences(of: "\r", with: "\n") + strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { let neta = strData[$0].split(separator: " ") if neta.count >= 2 { let theKey = String(neta[0]) - if !neta[0].isEmpty, !neta[1].isEmpty, theKey.first != "#" { - let theValue = $0 - rangeMap[theKey, default: []].append(theValue) + if !theKey.isEmpty, theKey.first != "#" { + for (i, _) in neta.filter({ $0.first != "#" && !$0.isEmpty }).enumerated() { + if i == 0 { continue } + rangeMap[theKey, default: []].append(($0, i)) + } } } } @@ -78,24 +81,16 @@ extension vChewing { } public func dump() { - var strDump = "" - for entry in rangeMap { - let netaRanges: [Range] = entry.value - for netaRange in netaRanges { - let neta = strData[netaRange] - let addline = neta + "\n" - strDump += addline - } - } - IME.prtDebugIntel(strDump) + // We remove this function in order to reduce out maintenance workload. + // This function will be implemented only if further hard-necessity comes. } - public func valuesFor(key: String) -> [String]? { + public func valuesFor(key: String) -> [String] { var pairs: [String] = [] - if let arrRangeRecords: [Range] = rangeMap[key] { - for netaRange in arrRangeRecords { + if let arrRangeRecords: [(Range, Int)] = rangeMap[key] { + for (netaRange, index) in arrRangeRecords { let neta = strData[netaRange].split(separator: " ") - let theValue: String = .init(neta[1]) + let theValue: String = .init(neta[index]) pairs.append(theValue) } } @@ -105,6 +100,40 @@ extension vChewing { public func hasValuesFor(key: String) -> Bool { rangeMap[key] != nil } + + public func valuesFor(pair: Megrez.KeyValuePaired) -> [String] { + var pairPinyin = pair + pairPinyin.key = Tekkon.cnvPhonaToHanyuPinyin(target: pairPinyin.key) + var pairs: [String] = [] + if let arrRangeRecords: [(Range, Int)] = rangeMap[pair.toNGramKey] { + for (netaRange, index) in arrRangeRecords { + let neta = strData[netaRange].split(separator: " ") + let theValue: String = .init(neta[index]) + pairs.append(theValue) + } + } + if let arrRangeRecords: [(Range, Int)] = rangeMap[pairPinyin.toNGramKey] { + for (netaRange, index) in arrRangeRecords { + let neta = strData[netaRange].split(separator: " ") + let theValue: String = .init(neta[index]) + pairs.append(theValue) + } + } + if let arrRangeRecords: [(Range, Int)] = rangeMap[pair.value] { + for (netaRange, index) in arrRangeRecords { + let neta = strData[netaRange].split(separator: " ") + let theValue: String = .init(neta[index]) + pairs.append(theValue) + } + } + var set = Set() + return pairs.filter { set.insert($0).inserted } + } + + public func hasValuesFor(pair: Megrez.KeyValuePaired) -> Bool { + if rangeMap[pair.toNGramKey] != nil { return true } + return rangeMap[pair.value] != nil + } } } diff --git a/Source/Modules/LangModelRelated/SubLMs/lmCoreEX.swift b/Source/Modules/LangModelRelated/SubLMs/lmCoreEX.swift index 49978808..6a91e82a 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmCoreEX.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmCoreEX.swift @@ -86,11 +86,13 @@ extension vChewing { do { strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ") - strData.ranges(splitBy: "\n").forEach { + strData = strData.replacingOccurrences(of: "\r", with: "\n") + strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { let neta = strData[$0].split(separator: " ") if neta.count >= 2, String(neta[0]).first != "#" { if !neta[0].isEmpty, !neta[1].isEmpty { - let theKey = shouldReverse ? String(neta[1]) : String(neta[0]) + var theKey = shouldReverse ? String(neta[1]) : String(neta[0]) + theKey.cnvPinyinToPhonabet() let theValue = $0 rangeMap[theKey, default: []].append(theValue) } @@ -153,7 +155,7 @@ extension vChewing { let theValue: String = shouldReverse ? String(neta[0]) : String(neta[1]) let kvPair = Megrez.KeyValuePaired(key: key, value: theValue) var theScore = defaultScore - if neta.count >= 3, !shouldForceDefaultScore { + if neta.count >= 3, !shouldForceDefaultScore, !neta[2].contains("#") { theScore = .init(String(neta[2])) ?? defaultScore } if theScore > 0 { @@ -190,3 +192,19 @@ extension String { } } } + +// MARK: - 拼音轉注音 + +extension String { + fileprivate mutating func cnvPinyinToPhonabet() { + if contains("_") { return } + for key in Tekkon.mapHanyuPinyin.keys { + guard let value = Tekkon.mapHanyuPinyin[key] else { continue } + self = replacingOccurrences(of: key, with: value) + } + for key in Tekkon.mapArayuruPinyinIntonation.keys { + guard let value = Tekkon.mapArayuruPinyinIntonation[key] else { continue } + self = replacingOccurrences(of: key, with: value) + } + } +} diff --git a/Source/Modules/LangModelRelated/SubLMs/lmReplacements.swift b/Source/Modules/LangModelRelated/SubLMs/lmReplacements.swift index f70cb1d7..d7df5a93 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmReplacements.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmReplacements.swift @@ -52,7 +52,8 @@ extension vChewing { do { strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ") - strData.ranges(splitBy: "\n").forEach { + strData = strData.replacingOccurrences(of: "\r", with: "\n") + strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { let neta = strData[$0].split(separator: " ") if neta.count >= 2 { let theKey = String(neta[0]) diff --git a/Source/Modules/LangModelRelated/mgrLangModel.swift b/Source/Modules/LangModelRelated/mgrLangModel.swift index 711f2b45..e79eda30 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.swift +++ b/Source/Modules/LangModelRelated/mgrLangModel.swift @@ -36,6 +36,14 @@ private var gLangModelCHT = vChewing.LMInstantiator() private var gUserOverrideModelCHS = vChewing.LMUserOverride() private var gUserOverrideModelCHT = vChewing.LMUserOverride() +/// 使用者辭典資料預設範例檔案名稱。 +private let kTemplateNameUserPhrases = "template-userphrases" +private let kTemplateNameUserReplacements = "template-replacements" +private let kTemplateNameUserExclusions = "template-exclusions" +private let kTemplateNameUserSymbolPhrases = "template-usersymbolphrases" +private let kTemplateNameUserAssociatesCHS = "template-associatedPhrases-chs" +private let kTemplateNameUserAssociatesCHT = "template-associatedPhrases-cht" + enum mgrLangModel { /// 寫幾個回傳函式、供其餘控制模組來讀取那些被設為 fileprivate 的器外變數。 public static var lmCHS: vChewing.LMInstantiator { gLangModelCHS } @@ -307,18 +315,20 @@ enum mgrLangModel { return true } - static func chkUserLMFilesExist(_ mode: InputMode) -> Bool { + @discardableResult static func chkUserLMFilesExist(_ mode: InputMode) -> Bool { if !userDataFolderExists { return false } /// SymbolNode 資料與 UserOverrideModel 半衰模組資料檔案不需要強行確保存在。 /// 前者的話,需要該檔案存在的人自己會建立。 /// 後者的話,你在敲字時自己就會建立。 - if !ensureFileExists(userPhrasesDataURL(mode)) - || !ensureFileExists(userAssociatesDataURL(mode)) - || !ensureFileExists(userFilteredDataURL(mode)) - || !ensureFileExists(userReplacementsDataURL(mode)) - || !ensureFileExists(userSymbolDataURL(mode)) + if !ensureFileExists(userPhrasesDataURL(mode), populateWithTemplate: kTemplateNameUserPhrases) + || !ensureFileExists( + userAssociatesDataURL(mode), + populateWithTemplate: mode == .imeModeCHS ? kTemplateNameUserAssociatesCHS : kTemplateNameUserAssociatesCHT) + || !ensureFileExists(userFilteredDataURL(mode), populateWithTemplate: kTemplateNameUserExclusions) + || !ensureFileExists(userReplacementsDataURL(mode), populateWithTemplate: kTemplateNameUserReplacements) + || !ensureFileExists(userSymbolDataURL(mode), populateWithTemplate: kTemplateNameUserSymbolPhrases) { return false } diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png index 61ece00e..c616e18e 100644 Binary files a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png and b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png differ diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png index 335fc33c..03d63737 100644 Binary files a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png and b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png differ diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png index fc8e9cde..3bfcbb18 100644 Binary files a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png and b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128.png new file mode 100644 index 00000000..5728defa Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128.png differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128X128.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128X128.png deleted file mode 100644 index 4cb43d4a..00000000 Binary files a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128X128.png and /dev/null differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192.png new file mode 100644 index 00000000..df988e34 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192.png differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192x192.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192x192.png deleted file mode 100644 index 8a87f7c6..00000000 Binary files a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192x192.png and /dev/null differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64.png new file mode 100644 index 00000000..2a24661f Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64.png differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64X64.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64X64.png deleted file mode 100644 index fe4c4ac7..00000000 Binary files a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64X64.png and /dev/null differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/Contents.json b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/Contents.json index 78b259ac..d0cdec0f 100644 --- a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/Contents.json +++ b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "64X64.png", + "filename" : "64.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "128X128.png", + "filename" : "128.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "192x192.png", + "filename" : "192.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png index 4a48f9ee..4bfc4300 100644 Binary files a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png index 4cb43d4a..5728defa 100644 Binary files a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png index 4050f62d..2f919dd6 100644 Binary files a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png index b729a95e..7a8707a4 100644 Binary files a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png index 9d0879cd..79236c1d 100644 Binary files a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png index fe4c4ac7..2a24661f 100644 Binary files a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png differ diff --git a/Source/Resources/Images/RAW/Study.heic b/Source/Resources/Images/RAW/Study.heic new file mode 100644 index 00000000..0fae7c42 Binary files /dev/null and b/Source/Resources/Images/RAW/Study.heic differ diff --git a/Source/Resources/template-exclusions.txt b/Source/Resources/template-exclusions.txt new file mode 100644 index 00000000..3a4df021 --- /dev/null +++ b/Source/Resources/template-exclusions.txt @@ -0,0 +1,12 @@ +# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍 +# 按照下述格式「字詞 注音-注音」的方式在本文內添入的字詞記錄會被輸入法的所有辭典都排除掉。 +# 按照下述格式「字词 注音-注音」的方式在本文内添入的字词记录会被输入法的所有辞典都排除掉。 +# 下記の格式「候補 注音-注音」のよう、このファイルで登録した入力候補は、全辞書から排除されます。 +# By using the format "Candidate Reading-Reading", all candidate pairs registered in this file will be blocked among all dictionaries. +# +# 北七 ㄅㄟˇ-ㄑㄧ +# +# 如果任何一行以半形英數「#」或者空格開頭,則該行將被忽略。 +# 如果任何一行以半角英数「#」或者空格开头,则该行将被忽略。 +# 頭文字が半角英数「#」或いは「スペース」の行は効けません。 +# Lines begin with an ASCII sharp symbol or a space will be omitted. diff --git a/Source/Resources/template-replacements.txt b/Source/Resources/template-replacements.txt new file mode 100644 index 00000000..555fd678 --- /dev/null +++ b/Source/Resources/template-replacements.txt @@ -0,0 +1,12 @@ +# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍 +# 按照下述格式「字詞 新字詞」的方式在本文內添入的字詞記錄才會生效。 +# 按照下述格式「字词 新字词」的方式在本文内添入的字词记录才会生效。 +# 下記の格式「候補 新候補」のよう、このファイルで登録した入力候補は効きます。 +# By using the format "Candidate NewCandidate", all entries registered in this file will be effective. +# +# 歐陽修 歐陽脩 +# +# 如果任何一行以半形英數「#」或者空格開頭,則該行將被忽略。 +# 如果任何一行以半角英数「#」或者空格开头,则该行将被忽略。 +# 頭文字が半角英数「#」或いは「スペース」の行は効けません。 +# Lines begin with an ASCII sharp symbol or a space will be omitted. diff --git a/Source/Resources/template-userphrases.txt b/Source/Resources/template-userphrases.txt new file mode 100644 index 00000000..b2455288 --- /dev/null +++ b/Source/Resources/template-userphrases.txt @@ -0,0 +1,12 @@ +# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍 +# 按照下述格式「字詞 注音-注音」的方式在本文內添入的字詞記錄才會生效。 +# 按照下述格式「字词 注音-注音」的方式在本文内添入的字词记录才会生效。 +# 下記の格式「候補 注音-注音」のよう、このファイルで登録した入力候補は効きます。 +# By using the format "Candidate Reading-Reading", all entries registered in this file will be effective. +# +# 我是自訂語彙 ㄨㄛˇ-ㄕˋ-ㄗˋ-ㄉㄧㄥˋ-ㄩˇ-ㄏㄨㄟˋ +# +# 如果任何一行以半形英數「#」或者空格開頭,則該行將被忽略。 +# 如果任何一行以半角英数「#」或者空格开头,则该行将被忽略。 +# 頭文字が半角英数「#」或いは「スペース」の行は効けません。 +# Lines begin with an ASCII sharp symbol or a space will be omitted. diff --git a/Source/Resources/template-usersymbolphrases.txt b/Source/Resources/template-usersymbolphrases.txt new file mode 100644 index 00000000..4419e49c --- /dev/null +++ b/Source/Resources/template-usersymbolphrases.txt @@ -0,0 +1,12 @@ +# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍 +# 按照下述格式「字詞 注音-注音」的方式在本文內添入的字詞記錄才會生效。 +# 按照下述格式「字词 注音-注音」的方式在本文内添入的字词记录才会生效。 +# 下記の格式「候補 注音-注音」のよう、このファイルで登録した入力候補は効きます。 +# By using the format "Candidate Reading-Reading", all entries registered in this file will be effective. +# +# ⚠︎ ㄐㄧㄥˇ-ㄍㄠˋ +# +# 如果任何一行以半形英數「#」或者空格開頭,則該行將被忽略。 +# 如果任何一行以半角英数「#」或者空格开头,则该行将被忽略。 +# 頭文字が半角英数「#」或いは「スペース」の行は効けません。 +# Lines begin with an ASCII sharp symbol or a space will be omitted. diff --git a/Update-Info.plist b/Update-Info.plist index b25f421b..38db6ae9 100644 --- a/Update-Info.plist +++ b/Update-Info.plist @@ -3,9 +3,9 @@ CFBundleShortVersionString - 1.8.0 + 1.8.1 CFBundleVersion - 1980 + 1981 UpdateInfoEndpoint https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist UpdateInfoSite diff --git a/UserPhraseEditor/Document.swift b/UserPhraseEditor/Document.swift index e7c025c2..79f53272 100644 --- a/UserPhraseEditor/Document.swift +++ b/UserPhraseEditor/Document.swift @@ -78,7 +78,7 @@ class Document: NSDocument { /// - Tag: readExample override func read(from data: Data, ofType _: String) throws { var strToDealWith = String(decoding: data, as: UTF8.self) - strToDealWith.formatConsolidate(cnvHYPYtoBPMF: false) + strToDealWith.formatConsolidate() let processedIncomingData = Data(strToDealWith.utf8) content.read(from: processedIncomingData) } @@ -86,7 +86,7 @@ class Document: NSDocument { /// - Tag: writeExample override func data(ofType _: String) throws -> Data { var strToDealWith = content.contentString - strToDealWith.formatConsolidate(cnvHYPYtoBPMF: true) + strToDealWith.formatConsolidate() let outputData = Data(strToDealWith.utf8) return outputData } diff --git a/UserPhraseEditor/StringExtension.swift b/UserPhraseEditor/StringExtension.swift index 747045a0..8baa5d8d 100644 --- a/UserPhraseEditor/StringExtension.swift +++ b/UserPhraseEditor/StringExtension.swift @@ -42,7 +42,7 @@ extension String { self = replacingOccurrences(of: strOf, with: strWith) } - mutating func formatConsolidate(cnvHYPYtoBPMF: Bool) { + mutating func formatConsolidate() { // Step 1: Consolidating formats per line. var strProcessed = self // 預處理格式 @@ -64,442 +64,6 @@ extension String { strProcessed.removeLast() } - if cnvHYPYtoBPMF { - // Step 2: Convert HanyuPinyin to Bopomofo. - // 漢語拼音轉注音,得先從最長的可能的拼音組合開始轉起, - // 這樣等轉換到更短的可能的漢語拼音組合時就不會出錯。 - // 依此類推,聲調放在最後來轉換。 - strProcessed.selfReplace("chuang", "ㄔㄨㄤ") - strProcessed.selfReplace("shuang", "ㄕㄨㄤ") - strProcessed.selfReplace("zhuang", "ㄓㄨㄤ") - strProcessed.selfReplace("chang", "ㄔㄤ") - strProcessed.selfReplace("cheng", "ㄔㄥ") - strProcessed.selfReplace("chong", "ㄔㄨㄥ") - strProcessed.selfReplace("chuai", "ㄔㄨㄞ") - strProcessed.selfReplace("chuan", "ㄔㄨㄢ") - strProcessed.selfReplace("guang", "ㄍㄨㄤ") - strProcessed.selfReplace("huang", "ㄏㄨㄤ") - strProcessed.selfReplace("jiang", "ㄐㄧㄤ") - strProcessed.selfReplace("jiong", "ㄐㄩㄥ") - strProcessed.selfReplace("kuang", "ㄎㄨㄤ") - strProcessed.selfReplace("liang", "ㄌㄧㄤ") - strProcessed.selfReplace("niang", "ㄋㄧㄤ") - strProcessed.selfReplace("qiang", "ㄑㄧㄤ") - strProcessed.selfReplace("qiong", "ㄑㄩㄥ") - strProcessed.selfReplace("shang", "ㄕㄤ") - strProcessed.selfReplace("sheng", "ㄕㄥ") - strProcessed.selfReplace("shuai", "ㄕㄨㄞ") - strProcessed.selfReplace("shuan", "ㄕㄨㄢ") - strProcessed.selfReplace("xiang", "ㄒㄧㄤ") - strProcessed.selfReplace("xiong", "ㄒㄩㄥ") - strProcessed.selfReplace("zhang", "ㄓㄤ") - strProcessed.selfReplace("zheng", "ㄓㄥ") - strProcessed.selfReplace("zhong", "ㄓㄨㄥ") - strProcessed.selfReplace("zhuai", "ㄓㄨㄞ") - strProcessed.selfReplace("zhuan", "ㄓㄨㄢ") - strProcessed.selfReplace("bang", "ㄅㄤ") - strProcessed.selfReplace("beng", "ㄅㄥ") - strProcessed.selfReplace("bian", "ㄅㄧㄢ") - strProcessed.selfReplace("biao", "ㄅㄧㄠ") - strProcessed.selfReplace("bing", "ㄅㄧㄥ") - strProcessed.selfReplace("cang", "ㄘㄤ") - strProcessed.selfReplace("ceng", "ㄘㄥ") - strProcessed.selfReplace("chai", "ㄔㄞ") - strProcessed.selfReplace("chan", "ㄔㄢ") - strProcessed.selfReplace("chao", "ㄔㄠ") - strProcessed.selfReplace("chen", "ㄔㄣ") - strProcessed.selfReplace("chou", "ㄔㄡ") - strProcessed.selfReplace("chua", "ㄔㄨㄚ") - strProcessed.selfReplace("chui", "ㄔㄨㄟ") - strProcessed.selfReplace("chun", "ㄔㄨㄣ") - strProcessed.selfReplace("chuo", "ㄔㄨㄛ") - strProcessed.selfReplace("cong", "ㄘㄨㄥ") - strProcessed.selfReplace("cuan", "ㄘㄨㄢ") - strProcessed.selfReplace("dang", "ㄉㄤ") - strProcessed.selfReplace("deng", "ㄉㄥ") - strProcessed.selfReplace("dian", "ㄉㄧㄢ") - strProcessed.selfReplace("diao", "ㄉㄧㄠ") - strProcessed.selfReplace("ding", "ㄉㄧㄥ") - strProcessed.selfReplace("dong", "ㄉㄨㄥ") - strProcessed.selfReplace("duan", "ㄉㄨㄢ") - strProcessed.selfReplace("fang", "ㄈㄤ") - strProcessed.selfReplace("feng", "ㄈㄥ") - strProcessed.selfReplace("fiao", "ㄈㄧㄠ") - strProcessed.selfReplace("fong", "ㄈㄨㄥ") - strProcessed.selfReplace("gang", "ㄍㄤ") - strProcessed.selfReplace("geng", "ㄍㄥ") - strProcessed.selfReplace("giao", "ㄍㄧㄠ") - strProcessed.selfReplace("gong", "ㄍㄨㄥ") - strProcessed.selfReplace("guai", "ㄍㄨㄞ") - strProcessed.selfReplace("guan", "ㄍㄨㄢ") - strProcessed.selfReplace("hang", "ㄏㄤ") - strProcessed.selfReplace("heng", "ㄏㄥ") - strProcessed.selfReplace("hong", "ㄏㄨㄥ") - strProcessed.selfReplace("huai", "ㄏㄨㄞ") - strProcessed.selfReplace("huan", "ㄏㄨㄢ") - strProcessed.selfReplace("jian", "ㄐㄧㄢ") - strProcessed.selfReplace("jiao", "ㄐㄧㄠ") - strProcessed.selfReplace("jing", "ㄐㄧㄥ") - strProcessed.selfReplace("juan", "ㄐㄩㄢ") - strProcessed.selfReplace("kang", "ㄎㄤ") - strProcessed.selfReplace("keng", "ㄎㄥ") - strProcessed.selfReplace("kong", "ㄎㄨㄥ") - strProcessed.selfReplace("kuai", "ㄎㄨㄞ") - strProcessed.selfReplace("kuan", "ㄎㄨㄢ") - strProcessed.selfReplace("lang", "ㄌㄤ") - strProcessed.selfReplace("leng", "ㄌㄥ") - strProcessed.selfReplace("lian", "ㄌㄧㄢ") - strProcessed.selfReplace("liao", "ㄌㄧㄠ") - strProcessed.selfReplace("ling", "ㄌㄧㄥ") - strProcessed.selfReplace("long", "ㄌㄨㄥ") - strProcessed.selfReplace("luan", "ㄌㄨㄢ") - strProcessed.selfReplace("lvan", "ㄌㄩㄢ") - strProcessed.selfReplace("mang", "ㄇㄤ") - strProcessed.selfReplace("meng", "ㄇㄥ") - strProcessed.selfReplace("mian", "ㄇㄧㄢ") - strProcessed.selfReplace("miao", "ㄇㄧㄠ") - strProcessed.selfReplace("ming", "ㄇㄧㄥ") - strProcessed.selfReplace("nang", "ㄋㄤ") - strProcessed.selfReplace("neng", "ㄋㄥ") - strProcessed.selfReplace("nian", "ㄋㄧㄢ") - strProcessed.selfReplace("niao", "ㄋㄧㄠ") - strProcessed.selfReplace("ning", "ㄋㄧㄥ") - strProcessed.selfReplace("nong", "ㄋㄨㄥ") - strProcessed.selfReplace("nuan", "ㄋㄨㄢ") - strProcessed.selfReplace("pang", "ㄆㄤ") - strProcessed.selfReplace("peng", "ㄆㄥ") - strProcessed.selfReplace("pian", "ㄆㄧㄢ") - strProcessed.selfReplace("piao", "ㄆㄧㄠ") - strProcessed.selfReplace("ping", "ㄆㄧㄥ") - strProcessed.selfReplace("qian", "ㄑㄧㄢ") - strProcessed.selfReplace("qiao", "ㄑㄧㄠ") - strProcessed.selfReplace("qing", "ㄑㄧㄥ") - strProcessed.selfReplace("quan", "ㄑㄩㄢ") - strProcessed.selfReplace("rang", "ㄖㄤ") - strProcessed.selfReplace("reng", "ㄖㄥ") - strProcessed.selfReplace("rong", "ㄖㄨㄥ") - strProcessed.selfReplace("ruan", "ㄖㄨㄢ") - strProcessed.selfReplace("sang", "ㄙㄤ") - strProcessed.selfReplace("seng", "ㄙㄥ") - strProcessed.selfReplace("shai", "ㄕㄞ") - strProcessed.selfReplace("shan", "ㄕㄢ") - strProcessed.selfReplace("shao", "ㄕㄠ") - strProcessed.selfReplace("shei", "ㄕㄟ") - strProcessed.selfReplace("shen", "ㄕㄣ") - strProcessed.selfReplace("shou", "ㄕㄡ") - strProcessed.selfReplace("shua", "ㄕㄨㄚ") - strProcessed.selfReplace("shui", "ㄕㄨㄟ") - strProcessed.selfReplace("shun", "ㄕㄨㄣ") - strProcessed.selfReplace("shuo", "ㄕㄨㄛ") - strProcessed.selfReplace("song", "ㄙㄨㄥ") - strProcessed.selfReplace("suan", "ㄙㄨㄢ") - strProcessed.selfReplace("tang", "ㄊㄤ") - strProcessed.selfReplace("teng", "ㄊㄥ") - strProcessed.selfReplace("tian", "ㄊㄧㄢ") - strProcessed.selfReplace("tiao", "ㄊㄧㄠ") - strProcessed.selfReplace("ting", "ㄊㄧㄥ") - strProcessed.selfReplace("tong", "ㄊㄨㄥ") - strProcessed.selfReplace("tuan", "ㄊㄨㄢ") - strProcessed.selfReplace("wang", "ㄨㄤ") - strProcessed.selfReplace("weng", "ㄨㄥ") - strProcessed.selfReplace("xian", "ㄒㄧㄢ") - strProcessed.selfReplace("xiao", "ㄒㄧㄠ") - strProcessed.selfReplace("xing", "ㄒㄧㄥ") - strProcessed.selfReplace("xuan", "ㄒㄩㄢ") - strProcessed.selfReplace("yang", "ㄧㄤ") - strProcessed.selfReplace("ying", "ㄧㄥ") - strProcessed.selfReplace("yong", "ㄩㄥ") - strProcessed.selfReplace("yuan", "ㄩㄢ") - strProcessed.selfReplace("zang", "ㄗㄤ") - strProcessed.selfReplace("zeng", "ㄗㄥ") - strProcessed.selfReplace("zhai", "ㄓㄞ") - strProcessed.selfReplace("zhan", "ㄓㄢ") - strProcessed.selfReplace("zhao", "ㄓㄠ") - strProcessed.selfReplace("zhei", "ㄓㄟ") - strProcessed.selfReplace("zhen", "ㄓㄣ") - strProcessed.selfReplace("zhou", "ㄓㄡ") - strProcessed.selfReplace("zhua", "ㄓㄨㄚ") - strProcessed.selfReplace("zhui", "ㄓㄨㄟ") - strProcessed.selfReplace("zhun", "ㄓㄨㄣ") - strProcessed.selfReplace("zhuo", "ㄓㄨㄛ") - strProcessed.selfReplace("zong", "ㄗㄨㄥ") - strProcessed.selfReplace("zuan", "ㄗㄨㄢ") - strProcessed.selfReplace("jun", "ㄐㄩㄣ") - strProcessed.selfReplace("ang", "ㄤ") - strProcessed.selfReplace("bai", "ㄅㄞ") - strProcessed.selfReplace("ban", "ㄅㄢ") - strProcessed.selfReplace("bao", "ㄅㄠ") - strProcessed.selfReplace("bei", "ㄅㄟ") - strProcessed.selfReplace("ben", "ㄅㄣ") - strProcessed.selfReplace("bie", "ㄅㄧㄝ") - strProcessed.selfReplace("bin", "ㄅㄧㄣ") - strProcessed.selfReplace("cai", "ㄘㄞ") - strProcessed.selfReplace("can", "ㄘㄢ") - strProcessed.selfReplace("cao", "ㄘㄠ") - strProcessed.selfReplace("cei", "ㄘㄟ") - strProcessed.selfReplace("cen", "ㄘㄣ") - strProcessed.selfReplace("cha", "ㄔㄚ") - strProcessed.selfReplace("che", "ㄔㄜ") - strProcessed.selfReplace("chi", "ㄔ") - strProcessed.selfReplace("chu", "ㄔㄨ") - strProcessed.selfReplace("cou", "ㄘㄡ") - strProcessed.selfReplace("cui", "ㄘㄨㄟ") - strProcessed.selfReplace("cun", "ㄘㄨㄣ") - strProcessed.selfReplace("cuo", "ㄘㄨㄛ") - strProcessed.selfReplace("dai", "ㄉㄞ") - strProcessed.selfReplace("dan", "ㄉㄢ") - strProcessed.selfReplace("dao", "ㄉㄠ") - strProcessed.selfReplace("dei", "ㄉㄟ") - strProcessed.selfReplace("den", "ㄉㄣ") - strProcessed.selfReplace("dia", "ㄉㄧㄚ") - strProcessed.selfReplace("die", "ㄉㄧㄝ") - strProcessed.selfReplace("diu", "ㄉㄧㄡ") - strProcessed.selfReplace("dou", "ㄉㄡ") - strProcessed.selfReplace("dui", "ㄉㄨㄟ") - strProcessed.selfReplace("dun", "ㄉㄨㄣ") - strProcessed.selfReplace("duo", "ㄉㄨㄛ") - strProcessed.selfReplace("eng", "ㄥ") - strProcessed.selfReplace("fan", "ㄈㄢ") - strProcessed.selfReplace("fei", "ㄈㄟ") - strProcessed.selfReplace("fen", "ㄈㄣ") - strProcessed.selfReplace("fou", "ㄈㄡ") - strProcessed.selfReplace("gai", "ㄍㄞ") - strProcessed.selfReplace("gan", "ㄍㄢ") - strProcessed.selfReplace("gao", "ㄍㄠ") - strProcessed.selfReplace("gei", "ㄍㄟ") - strProcessed.selfReplace("gin", "ㄍㄧㄣ") - strProcessed.selfReplace("gen", "ㄍㄣ") - strProcessed.selfReplace("gou", "ㄍㄡ") - strProcessed.selfReplace("gua", "ㄍㄨㄚ") - strProcessed.selfReplace("gue", "ㄍㄨㄜ") - strProcessed.selfReplace("gui", "ㄍㄨㄟ") - strProcessed.selfReplace("gun", "ㄍㄨㄣ") - strProcessed.selfReplace("guo", "ㄍㄨㄛ") - strProcessed.selfReplace("hai", "ㄏㄞ") - strProcessed.selfReplace("han", "ㄏㄢ") - strProcessed.selfReplace("hao", "ㄏㄠ") - strProcessed.selfReplace("hei", "ㄏㄟ") - strProcessed.selfReplace("hen", "ㄏㄣ") - strProcessed.selfReplace("hou", "ㄏㄡ") - strProcessed.selfReplace("hua", "ㄏㄨㄚ") - strProcessed.selfReplace("hui", "ㄏㄨㄟ") - strProcessed.selfReplace("hun", "ㄏㄨㄣ") - strProcessed.selfReplace("huo", "ㄏㄨㄛ") - strProcessed.selfReplace("jia", "ㄐㄧㄚ") - strProcessed.selfReplace("jie", "ㄐㄧㄝ") - strProcessed.selfReplace("jin", "ㄐㄧㄣ") - strProcessed.selfReplace("jiu", "ㄐㄧㄡ") - strProcessed.selfReplace("jue", "ㄐㄩㄝ") - strProcessed.selfReplace("kai", "ㄎㄞ") - strProcessed.selfReplace("kan", "ㄎㄢ") - strProcessed.selfReplace("kao", "ㄎㄠ") - strProcessed.selfReplace("ken", "ㄎㄣ") - strProcessed.selfReplace("kiu", "ㄎㄧㄡ") - strProcessed.selfReplace("kou", "ㄎㄡ") - strProcessed.selfReplace("kua", "ㄎㄨㄚ") - strProcessed.selfReplace("kui", "ㄎㄨㄟ") - strProcessed.selfReplace("kun", "ㄎㄨㄣ") - strProcessed.selfReplace("kuo", "ㄎㄨㄛ") - strProcessed.selfReplace("lai", "ㄌㄞ") - strProcessed.selfReplace("lan", "ㄌㄢ") - strProcessed.selfReplace("lao", "ㄌㄠ") - strProcessed.selfReplace("lei", "ㄌㄟ") - strProcessed.selfReplace("lia", "ㄌㄧㄚ") - strProcessed.selfReplace("lie", "ㄌㄧㄝ") - strProcessed.selfReplace("lin", "ㄌㄧㄣ") - strProcessed.selfReplace("liu", "ㄌㄧㄡ") - strProcessed.selfReplace("lou", "ㄌㄡ") - strProcessed.selfReplace("lun", "ㄌㄨㄣ") - strProcessed.selfReplace("luo", "ㄌㄨㄛ") - strProcessed.selfReplace("lve", "ㄌㄩㄝ") - strProcessed.selfReplace("mai", "ㄇㄞ") - strProcessed.selfReplace("man", "ㄇㄢ") - strProcessed.selfReplace("mao", "ㄇㄠ") - strProcessed.selfReplace("mei", "ㄇㄟ") - strProcessed.selfReplace("men", "ㄇㄣ") - strProcessed.selfReplace("mie", "ㄇㄧㄝ") - strProcessed.selfReplace("min", "ㄇㄧㄣ") - strProcessed.selfReplace("miu", "ㄇㄧㄡ") - strProcessed.selfReplace("mou", "ㄇㄡ") - strProcessed.selfReplace("nai", "ㄋㄞ") - strProcessed.selfReplace("nan", "ㄋㄢ") - strProcessed.selfReplace("nao", "ㄋㄠ") - strProcessed.selfReplace("nei", "ㄋㄟ") - strProcessed.selfReplace("nen", "ㄋㄣ") - strProcessed.selfReplace("nie", "ㄋㄧㄝ") - strProcessed.selfReplace("nin", "ㄋㄧㄣ") - strProcessed.selfReplace("niu", "ㄋㄧㄡ") - strProcessed.selfReplace("nou", "ㄋㄡ") - strProcessed.selfReplace("nui", "ㄋㄨㄟ") - strProcessed.selfReplace("nun", "ㄋㄨㄣ") - strProcessed.selfReplace("nuo", "ㄋㄨㄛ") - strProcessed.selfReplace("nve", "ㄋㄩㄝ") - strProcessed.selfReplace("pai", "ㄆㄞ") - strProcessed.selfReplace("pan", "ㄆㄢ") - strProcessed.selfReplace("pao", "ㄆㄠ") - strProcessed.selfReplace("pei", "ㄆㄟ") - strProcessed.selfReplace("pen", "ㄆㄣ") - strProcessed.selfReplace("pia", "ㄆㄧㄚ") - strProcessed.selfReplace("pie", "ㄆㄧㄝ") - strProcessed.selfReplace("pin", "ㄆㄧㄣ") - strProcessed.selfReplace("pou", "ㄆㄡ") - strProcessed.selfReplace("qia", "ㄑㄧㄚ") - strProcessed.selfReplace("qie", "ㄑㄧㄝ") - strProcessed.selfReplace("qin", "ㄑㄧㄣ") - strProcessed.selfReplace("qiu", "ㄑㄧㄡ") - strProcessed.selfReplace("que", "ㄑㄩㄝ") - strProcessed.selfReplace("qun", "ㄑㄩㄣ") - strProcessed.selfReplace("ran", "ㄖㄢ") - strProcessed.selfReplace("rao", "ㄖㄠ") - strProcessed.selfReplace("ren", "ㄖㄣ") - strProcessed.selfReplace("rou", "ㄖㄡ") - strProcessed.selfReplace("rui", "ㄖㄨㄟ") - strProcessed.selfReplace("run", "ㄖㄨㄣ") - strProcessed.selfReplace("ruo", "ㄖㄨㄛ") - strProcessed.selfReplace("sai", "ㄙㄞ") - strProcessed.selfReplace("san", "ㄙㄢ") - strProcessed.selfReplace("sao", "ㄙㄠ") - strProcessed.selfReplace("sei", "ㄙㄟ") - strProcessed.selfReplace("sen", "ㄙㄣ") - strProcessed.selfReplace("sha", "ㄕㄚ") - strProcessed.selfReplace("she", "ㄕㄜ") - strProcessed.selfReplace("shi", "ㄕ") - strProcessed.selfReplace("shu", "ㄕㄨ") - strProcessed.selfReplace("sou", "ㄙㄡ") - strProcessed.selfReplace("sui", "ㄙㄨㄟ") - strProcessed.selfReplace("sun", "ㄙㄨㄣ") - strProcessed.selfReplace("suo", "ㄙㄨㄛ") - strProcessed.selfReplace("tai", "ㄊㄞ") - strProcessed.selfReplace("tan", "ㄊㄢ") - strProcessed.selfReplace("tao", "ㄊㄠ") - strProcessed.selfReplace("tie", "ㄊㄧㄝ") - strProcessed.selfReplace("tou", "ㄊㄡ") - strProcessed.selfReplace("tui", "ㄊㄨㄟ") - strProcessed.selfReplace("tun", "ㄊㄨㄣ") - strProcessed.selfReplace("tuo", "ㄊㄨㄛ") - strProcessed.selfReplace("wai", "ㄨㄞ") - strProcessed.selfReplace("wan", "ㄨㄢ") - strProcessed.selfReplace("wei", "ㄨㄟ") - strProcessed.selfReplace("wen", "ㄨㄣ") - strProcessed.selfReplace("xia", "ㄒㄧㄚ") - strProcessed.selfReplace("xie", "ㄒㄧㄝ") - strProcessed.selfReplace("xin", "ㄒㄧㄣ") - strProcessed.selfReplace("xiu", "ㄒㄧㄡ") - strProcessed.selfReplace("xue", "ㄒㄩㄝ") - strProcessed.selfReplace("xun", "ㄒㄩㄣ") - strProcessed.selfReplace("yai", "ㄧㄞ") - strProcessed.selfReplace("yan", "ㄧㄢ") - strProcessed.selfReplace("yao", "ㄧㄠ") - strProcessed.selfReplace("yin", "ㄧㄣ") - strProcessed.selfReplace("you", "ㄧㄡ") - strProcessed.selfReplace("yue", "ㄩㄝ") - strProcessed.selfReplace("yun", "ㄩㄣ") - strProcessed.selfReplace("zai", "ㄗㄞ") - strProcessed.selfReplace("zan", "ㄗㄢ") - strProcessed.selfReplace("zao", "ㄗㄠ") - strProcessed.selfReplace("zei", "ㄗㄟ") - strProcessed.selfReplace("zen", "ㄗㄣ") - strProcessed.selfReplace("zha", "ㄓㄚ") - strProcessed.selfReplace("zhe", "ㄓㄜ") - strProcessed.selfReplace("zhi", "ㄓ") - strProcessed.selfReplace("zhu", "ㄓㄨ") - strProcessed.selfReplace("zou", "ㄗㄡ") - strProcessed.selfReplace("zui", "ㄗㄨㄟ") - strProcessed.selfReplace("zun", "ㄗㄨㄣ") - strProcessed.selfReplace("zuo", "ㄗㄨㄛ") - strProcessed.selfReplace("ai", "ㄞ") - strProcessed.selfReplace("an", "ㄢ") - strProcessed.selfReplace("ao", "ㄠ") - strProcessed.selfReplace("ba", "ㄅㄚ") - strProcessed.selfReplace("bi", "ㄅㄧ") - strProcessed.selfReplace("bo", "ㄅㄛ") - strProcessed.selfReplace("bu", "ㄅㄨ") - strProcessed.selfReplace("ca", "ㄘㄚ") - strProcessed.selfReplace("ce", "ㄘㄜ") - strProcessed.selfReplace("ci", "ㄘ") - strProcessed.selfReplace("cu", "ㄘㄨ") - strProcessed.selfReplace("da", "ㄉㄚ") - strProcessed.selfReplace("de", "ㄉㄜ") - strProcessed.selfReplace("di", "ㄉㄧ") - strProcessed.selfReplace("du", "ㄉㄨ") - strProcessed.selfReplace("eh", "ㄝ") - strProcessed.selfReplace("ei", "ㄟ") - strProcessed.selfReplace("en", "ㄣ") - strProcessed.selfReplace("er", "ㄦ") - strProcessed.selfReplace("fa", "ㄈㄚ") - strProcessed.selfReplace("fo", "ㄈㄛ") - strProcessed.selfReplace("fu", "ㄈㄨ") - strProcessed.selfReplace("ga", "ㄍㄚ") - strProcessed.selfReplace("ge", "ㄍㄜ") - strProcessed.selfReplace("gi", "ㄍㄧ") - strProcessed.selfReplace("gu", "ㄍㄨ") - strProcessed.selfReplace("ha", "ㄏㄚ") - strProcessed.selfReplace("he", "ㄏㄜ") - strProcessed.selfReplace("hu", "ㄏㄨ") - strProcessed.selfReplace("ji", "ㄐㄧ") - strProcessed.selfReplace("ju", "ㄐㄩ") - strProcessed.selfReplace("ka", "ㄎㄚ") - strProcessed.selfReplace("ke", "ㄎㄜ") - strProcessed.selfReplace("ku", "ㄎㄨ") - strProcessed.selfReplace("la", "ㄌㄚ") - strProcessed.selfReplace("le", "ㄌㄜ") - strProcessed.selfReplace("li", "ㄌㄧ") - strProcessed.selfReplace("lo", "ㄌㄛ") - strProcessed.selfReplace("lu", "ㄌㄨ") - strProcessed.selfReplace("lv", "ㄌㄩ") - strProcessed.selfReplace("ma", "ㄇㄚ") - strProcessed.selfReplace("me", "ㄇㄜ") - strProcessed.selfReplace("mi", "ㄇㄧ") - strProcessed.selfReplace("mo", "ㄇㄛ") - strProcessed.selfReplace("mu", "ㄇㄨ") - strProcessed.selfReplace("na", "ㄋㄚ") - strProcessed.selfReplace("ne", "ㄋㄜ") - strProcessed.selfReplace("ni", "ㄋㄧ") - strProcessed.selfReplace("nu", "ㄋㄨ") - strProcessed.selfReplace("nv", "ㄋㄩ") - strProcessed.selfReplace("ou", "ㄡ") - strProcessed.selfReplace("pa", "ㄆㄚ") - strProcessed.selfReplace("pi", "ㄆㄧ") - strProcessed.selfReplace("po", "ㄆㄛ") - strProcessed.selfReplace("pu", "ㄆㄨ") - strProcessed.selfReplace("qi", "ㄑㄧ") - strProcessed.selfReplace("qu", "ㄑㄩ") - strProcessed.selfReplace("re", "ㄖㄜ") - strProcessed.selfReplace("ri", "ㄖ") - strProcessed.selfReplace("ru", "ㄖㄨ") - strProcessed.selfReplace("sa", "ㄙㄚ") - strProcessed.selfReplace("se", "ㄙㄜ") - strProcessed.selfReplace("si", "ㄙ") - strProcessed.selfReplace("su", "ㄙㄨ") - strProcessed.selfReplace("ta", "ㄊㄚ") - strProcessed.selfReplace("te", "ㄊㄜ") - strProcessed.selfReplace("ti", "ㄊㄧ") - strProcessed.selfReplace("tu", "ㄊㄨ") - strProcessed.selfReplace("wa", "ㄨㄚ") - strProcessed.selfReplace("wo", "ㄨㄛ") - strProcessed.selfReplace("wu", "ㄨ") - strProcessed.selfReplace("xi", "ㄒㄧ") - strProcessed.selfReplace("xu", "ㄒㄩ") - strProcessed.selfReplace("ya", "ㄧㄚ") - strProcessed.selfReplace("ye", "ㄧㄝ") - strProcessed.selfReplace("yi", "ㄧ") - strProcessed.selfReplace("yo", "ㄧㄛ") - strProcessed.selfReplace("yu", "ㄩ") - strProcessed.selfReplace("za", "ㄗㄚ") - strProcessed.selfReplace("ze", "ㄗㄜ") - strProcessed.selfReplace("zi", "ㄗ") - strProcessed.selfReplace("zu", "ㄗㄨ") - strProcessed.selfReplace("a", "ㄚ") - strProcessed.selfReplace("e", "ㄜ") - strProcessed.selfReplace("o", "ㄛ") - strProcessed.selfReplace("q", "ㄑ") - strProcessed.selfReplace("2", "ˊ") - strProcessed.selfReplace("3", "ˇ") - strProcessed.selfReplace("4", "ˋ") - strProcessed.selfReplace("5", "˙") - strProcessed.selfReplace("1", "") - } - // Step 3: Add Formatted Pragma, the Sorted Header: let hdrFormatted = "# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍\n" strProcessed = hdrFormatted + strProcessed // Add Sorted Header diff --git a/vChewing.pkgproj b/vChewing.pkgproj index 810f13ff..91b0b9f3 100644 --- a/vChewing.pkgproj +++ b/vChewing.pkgproj @@ -726,7 +726,7 @@ USE_HFS+_COMPRESSION VERSION - 1.8.0 + 1.8.1 TYPE 0 diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 526ff0ff..b758fc05 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -109,6 +109,12 @@ 5BEDB723283B4C250078EB25 /* data-cht.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB720283B4AEA0078EB25 /* data-cht.plist */; }; 5BEDB724283B4C250078EB25 /* data-symbols.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB71E283B4AEA0078EB25 /* data-symbols.plist */; }; 5BEDB725283B4C250078EB25 /* data-chs.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB71C283B4AEA0078EB25 /* data-chs.plist */; }; + 5BF9DA2728840E6200DBD48E /* template-usersymbolphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */; }; + 5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2328840E6200DBD48E /* template-exclusions.txt */; }; + 5BF9DA2928840E6200DBD48E /* template-associatedPhrases-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */; }; + 5BF9DA2A28840E6200DBD48E /* template-replacements.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2528840E6200DBD48E /* template-replacements.txt */; }; + 5BF9DA2B28840E6200DBD48E /* template-userphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */; }; + 5BF9DA2D288427E000DBD48E /* template-associatedPhrases-cht.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */; }; 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; }; 6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; }; 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; }; @@ -306,6 +312,12 @@ 5BEDB71E283B4AEA0078EB25 /* data-symbols.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-symbols.plist"; path = "Data/data-symbols.plist"; sourceTree = ""; }; 5BEDB71F283B4AEA0078EB25 /* data-zhuyinwen.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-zhuyinwen.plist"; path = "Data/data-zhuyinwen.plist"; sourceTree = ""; }; 5BEDB720283B4AEA0078EB25 /* data-cht.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-cht.plist"; path = "Data/data-cht.plist"; sourceTree = ""; }; + 5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-usersymbolphrases.txt"; sourceTree = ""; usesTabs = 0; }; + 5BF9DA2328840E6200DBD48E /* template-exclusions.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-exclusions.txt"; sourceTree = ""; usesTabs = 0; }; + 5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-chs.txt"; path = "../Data/components/chs/template-associatedPhrases-chs.txt"; sourceTree = ""; usesTabs = 0; }; + 5BF9DA2528840E6200DBD48E /* template-replacements.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-replacements.txt"; sourceTree = ""; usesTabs = 0; }; + 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-userphrases.txt"; sourceTree = ""; usesTabs = 0; }; + 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-cht.txt"; path = "../Data/components/cht/template-associatedPhrases-cht.txt"; sourceTree = ""; }; 5BFDF48C27B51867009523B6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = ""; }; 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vChewing.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6A0D4EF515FC0DA600ABF4B3 /* IME-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "IME-Info.plist"; sourceTree = ""; }; @@ -502,6 +514,12 @@ 5B62A33027AE78E500A19448 /* Resources */ = { isa = PBXGroup; children = ( + 5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */, + 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */, + 5BF9DA2328840E6200DBD48E /* template-exclusions.txt */, + 5BF9DA2528840E6200DBD48E /* template-replacements.txt */, + 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */, + 5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */, 6A0D4EEE15FC0DA600ABF4B3 /* Images */, 5BBBB76E27AED70B0023B93A /* MenuIcons */, 5BBBB75C27AED54C0023B93A /* SoundFiles */, @@ -860,9 +878,9 @@ isa = PBXNativeTarget; buildConfigurationList = 6A0D4EC015FC0D2E00ABF4B3 /* Build configuration list for PBXNativeTarget "vChewing" */; buildPhases = ( - 5B9A5A00285184BB001FFCAF /* ShellScript */, 6A0D4E9E15FC0D2D00ABF4B3 /* Sources */, 6A0D4E9F15FC0D2D00ABF4B3 /* Frameworks */, + 5B9A5A00285184BB001FFCAF /* ShellScript */, 6A0D4EA015FC0D2D00ABF4B3 /* Resources */, 5BDC5CBE27C28E8B00E1CCE2 /* Embed Foundation Extensions */, ); @@ -984,6 +1002,7 @@ 5B84579E2871AD2200C93B01 /* convdict.plist in Resources */, 5BBBB77427AED70B0023B93A /* MenuIcon-SCVIM@2x.png in Resources */, D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */, + 5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */, 5BDCBB2E27B4E67A00D0CC59 /* vChewingPhraseEditor.app in Resources */, 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */, 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */, @@ -991,12 +1010,17 @@ 5BBBB76B27AED5DB0023B93A /* frmNonModalAlertWindow.xib in Resources */, 5BEDB723283B4C250078EB25 /* data-cht.plist in Resources */, 5BEDB721283B4C250078EB25 /* data-cns.plist in Resources */, + 5BF9DA2D288427E000DBD48E /* template-associatedPhrases-cht.txt in Resources */, 5BEDB725283B4C250078EB25 /* data-chs.plist in Resources */, + 5BF9DA2928840E6200DBD48E /* template-associatedPhrases-chs.txt in Resources */, 5BBBB76D27AED5DB0023B93A /* frmAboutWindow.xib in Resources */, + 5BF9DA2B28840E6200DBD48E /* template-userphrases.txt in Resources */, 5BBBB77527AED70B0023B93A /* MenuIcon-SCVIM.png in Resources */, 5BEDB722283B4C250078EB25 /* data-zhuyinwen.plist in Resources */, + 5BF9DA2728840E6200DBD48E /* template-usersymbolphrases.txt in Resources */, 5BEDB724283B4C250078EB25 /* data-symbols.plist in Resources */, 5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */, + 5BF9DA2A28840E6200DBD48E /* template-replacements.txt in Resources */, 5BBBB77327AED70B0023B93A /* MenuIcon-TCVIM@2x.png in Resources */, 5BBBB77627AED70B0023B93A /* MenuIcon-TCVIM.png in Resources */, 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */, @@ -1365,7 +1389,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -1375,7 +1399,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests; @@ -1404,13 +1428,13 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests; @@ -1441,7 +1465,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; DEAD_CODE_STRIPPING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; @@ -1462,7 +1486,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1491,7 +1515,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; DEAD_CODE_STRIPPING = YES; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1508,7 +1532,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1618,7 +1642,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; @@ -1649,7 +1673,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1676,7 +1700,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; @@ -1701,7 +1725,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1723,7 +1747,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1744,7 +1768,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1766,7 +1790,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1980; + CURRENT_PROJECT_VERSION = 1981; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1781,7 +1805,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.8.0; + MARKETING_VERSION = 1.8.1; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "";