Repo // Introducing PhraseEditorUI and its delegate protocol.

This commit is contained in:
ShikiSuen 2022-12-02 19:52:25 +08:00
parent 5dbbb0fcfa
commit 9f72ecc88a
10 changed files with 518 additions and 0 deletions

View File

@ -0,0 +1,30 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "PhraseEditorUI",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "PhraseEditorUI",
targets: ["PhraseEditorUI"]
)
],
dependencies: [
.package(path: "../vChewing_LangModelAssembly"),
.package(path: "../vChewing_Shared"),
.package(path: "../ShapsBenkau_SwiftUIBackports"),
],
targets: [
.target(
name: "PhraseEditorUI",
dependencies: [
.product(name: "LangModelAssembly", package: "vChewing_LangModelAssembly"),
.product(name: "SwiftUIBackports", package: "ShapsBenkau_SwiftUIBackports"),
.product(name: "Shared", package: "vChewing_Shared"),
]
)
]
)

View File

@ -0,0 +1,13 @@
# PhraseEditorUI
威注音語彙編輯器。
```
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// No trademark license is granted to use the trade names, trademarks, service
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
```

View File

@ -0,0 +1,21 @@
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// No trademark license is granted to use the trade names, trademarks, service
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
import Foundation
import LangModelAssembly
import Shared
public protocol PhraseEditorDelegate {
var currentInputMode: Shared.InputMode { get }
func retrieveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType) -> String
@discardableResult func saveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, data: String)
-> String
func checkIfUserPhraseExist(userPhrase: String, mode: Shared.InputMode, key unigramKey: String) -> Bool
func consolidate(text strProcessed: inout String, pragma shouldCheckPragma: Bool)
func openPhraseFile(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, app: String)
}

View File

@ -0,0 +1,345 @@
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// No trademark license is granted to use the trade names, trademarks, service
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
import Combine
import Foundation
import LangModelAssembly
import Shared
import SwiftExtension
import SwiftUI
import SwiftUIBackports
private let loc: String =
(UserDefaults.standard.array(forKey: UserDef.kAppleLanguages.rawValue) as? [String] ?? ["auto"])[0]
@available(macOS 10.15, *)
extension VwrPhraseEditorUI {
@Backport.AppStorage("PhraseEditorAutoReloadExternalModifications")
private static var autoReloadExternalModifications: Bool = true
}
@available(macOS 10.15, *)
public struct VwrPhraseEditorUI: View {
static var txtContentStorage: String = NSLocalizedString(
"Please select Simplified / Traditional Chinese mode above.", comment: ""
)
@Binding public var txtContent: String
@ObservedObject public var fileChangeIndicator = FileObserveProject.shared
@State private var selAutoReloadExternalModifications: Bool = UserDefaults.standard.bool(
forKey: UserDef.kPhraseEditorAutoReloadExternalModifications.rawValue)
@State var lblAddPhraseTag1 = UITerms.AddPhrases.locPhrase.localized.0
@State var lblAddPhraseTag2 = UITerms.AddPhrases.locReadingOrStroke.localized.0
@State var lblAddPhraseTag3 = UITerms.AddPhrases.locWeight.localized.0
@State var lblAddPhraseTag4 = UITerms.AddPhrases.locComment.localized.0
@State var txtAddPhraseField1 = ""
@State var txtAddPhraseField2 = ""
@State var txtAddPhraseField3 = ""
@State var txtAddPhraseField4 = ""
@State public var selInputMode: Shared.InputMode = .imeModeNULL
@State public var selUserDataType: vChewingLM.ReplacableUserDataType = .thePhrases
@State private var isLoading = false
@State private var isSaved = false
@State private var redrawTrigger = false
public var currentIMEInputMode: Shared.InputMode {
delegate?.currentInputMode ?? selInputMode
}
public var delegate: PhraseEditorDelegate? {
didSet {
guard let delegate = delegate else { return }
selInputMode = delegate.currentInputMode
update()
}
}
// MARK: -
public init(delegate theDelegate: PhraseEditorDelegate? = nil) {
_txtContent = .init(
get: { Self.txtContentStorage },
set: { newValue, _ in
Self.txtContentStorage.removeAll()
Self.txtContentStorage.append(newValue)
}
)
guard let theDelegate = theDelegate else { return }
defer { delegate = theDelegate }
}
public func update() {
guard let delegate = delegate else { return }
updateLabels()
clearAllFields()
isLoading = true
txtContent = NSLocalizedString("Loading…", comment: "")
redrawTrigger.toggle()
DispatchQueue.main.async {
txtContent = delegate.retrieveData(mode: selInputMode, type: selUserDataType)
redrawTrigger.toggle()
isSaved = true
isLoading = false
}
}
private func updateLabels() {
clearAllFields()
switch selUserDataType {
case .thePhrases:
lblAddPhraseTag1 = UITerms.AddPhrases.locPhrase.localized.0
lblAddPhraseTag2 = UITerms.AddPhrases.locReadingOrStroke.localized.0
lblAddPhraseTag3 = UITerms.AddPhrases.locWeight.localized.0
lblAddPhraseTag4 = UITerms.AddPhrases.locComment.localized.0
case .theFilter:
lblAddPhraseTag1 = UITerms.AddPhrases.locPhrase.localized.0
lblAddPhraseTag2 = UITerms.AddPhrases.locReadingOrStroke.localized.0
lblAddPhraseTag3 = ""
lblAddPhraseTag4 = UITerms.AddPhrases.locComment.localized.0
case .theReplacements:
lblAddPhraseTag1 = UITerms.AddPhrases.locReplaceTo.localized.0
lblAddPhraseTag2 = UITerms.AddPhrases.locReplaceTo.localized.1
lblAddPhraseTag3 = ""
lblAddPhraseTag4 = UITerms.AddPhrases.locComment.localized.0
case .theAssociates:
lblAddPhraseTag1 = UITerms.AddPhrases.locInitial.localized.0
lblAddPhraseTag2 = {
let result = UITerms.AddPhrases.locPhrase.localized.0
return (result == "Phrase") ? "Phrases" : result
}()
lblAddPhraseTag3 = ""
lblAddPhraseTag4 = ""
case .theSymbols:
lblAddPhraseTag1 = UITerms.AddPhrases.locPhrase.localized.0
lblAddPhraseTag2 = UITerms.AddPhrases.locReadingOrStroke.localized.0
lblAddPhraseTag3 = ""
lblAddPhraseTag4 = UITerms.AddPhrases.locComment.localized.0
}
}
private func insertEntry() {
txtAddPhraseField1.removeAll { "  \t\n\r".contains($0) }
if selUserDataType != .theAssociates {
txtAddPhraseField2.regReplace(pattern: #"( +| +| +|\t+)+"#, replaceWith: "-")
}
txtAddPhraseField2.removeAll {
selUserDataType == .theAssociates ? "\n\r".contains($0) : "  \t\n\r".contains($0)
}
txtAddPhraseField3.removeAll { !"0123456789.-".contains($0) }
txtAddPhraseField4.removeAll { "\n\r".contains($0) }
guard !txtAddPhraseField1.isEmpty, !txtAddPhraseField2.isEmpty else { return }
var arrResult: [String] = [txtAddPhraseField1, txtAddPhraseField2]
if let weightVal = Double(txtAddPhraseField3), weightVal < 0 {
arrResult.append(weightVal.description)
}
if !txtAddPhraseField4.isEmpty { arrResult.append("#" + txtAddPhraseField4) }
if let delegate = delegate,
delegate.checkIfUserPhraseExist(
userPhrase: txtAddPhraseField1, mode: selInputMode, key: txtAddPhraseField2
)
{
arrResult.append("\t#𝙾𝚟𝚎𝚛𝚛𝚒𝚍𝚎")
}
if let lastChar = txtContent.last, !"\n".contains(lastChar) {
arrResult.insert("\n", at: 0)
}
txtContent.append(arrResult.joined(separator: " ") + "\n")
isSaved = false
clearAllFields()
}
private func clearAllFields() {
txtAddPhraseField1 = ""
txtAddPhraseField2 = ""
txtAddPhraseField3 = ""
txtAddPhraseField4 = ""
}
private func dropDownMenuDidChange() {
update()
}
private func saveAndReload() {
guard let delegate = delegate, selInputMode != .imeModeNULL, !isSaved else { return }
let toSave = txtContent
isLoading = true
txtContent = NSLocalizedString("Loading…", comment: "")
redrawTrigger.toggle()
let newResult = delegate.saveData(mode: selInputMode, type: selUserDataType, data: toSave)
txtContent = newResult
redrawTrigger.toggle()
isLoading = false
isSaved = true
}
private func consolidate() {
guard let delegate = delegate, selInputMode != .imeModeNULL else { return }
DispatchQueue.main.async {
isLoading = true
delegate.consolidate(text: &txtContent, pragma: false) //
isLoading = false
isSaved = false
}
}
private func callExternalAppToOpenPhraseFile() {
delegate?.openPhraseFile(mode: selInputMode, type: selUserDataType, app: "Finder")
}
// MARK: - Main View.
public var body: some View {
VStack(spacing: 4) {
HStack {
Picker("", selection: $selInputMode.onChange { dropDownMenuDidChange() }) {
switch currentIMEInputMode {
case .imeModeCHS:
Text(Shared.InputMode.imeModeCHS.localizedDescription).tag(Shared.InputMode.imeModeCHS)
Text(Shared.InputMode.imeModeCHT.localizedDescription).tag(Shared.InputMode.imeModeCHT)
case .imeModeCHT:
Text(Shared.InputMode.imeModeCHT.localizedDescription).tag(Shared.InputMode.imeModeCHT)
Text(Shared.InputMode.imeModeCHS.localizedDescription).tag(Shared.InputMode.imeModeCHS)
case .imeModeNULL:
Text(Shared.InputMode.imeModeNULL.localizedDescription).tag(Shared.InputMode.imeModeNULL)
if loc.contains("Hans") {
Text(Shared.InputMode.imeModeCHS.localizedDescription).tag(Shared.InputMode.imeModeCHS)
Text(Shared.InputMode.imeModeCHT.localizedDescription).tag(Shared.InputMode.imeModeCHT)
} else {
Text(Shared.InputMode.imeModeCHT.localizedDescription).tag(Shared.InputMode.imeModeCHT)
Text(Shared.InputMode.imeModeCHS.localizedDescription).tag(Shared.InputMode.imeModeCHS)
}
}
}
.labelsHidden()
Picker("", selection: $selUserDataType.onChange { dropDownMenuDidChange() }) {
Text(vChewingLM.ReplacableUserDataType.thePhrases.localizedDescription).tag(
vChewingLM.ReplacableUserDataType.thePhrases)
Text(vChewingLM.ReplacableUserDataType.theFilter.localizedDescription).tag(
vChewingLM.ReplacableUserDataType.theFilter)
Text(vChewingLM.ReplacableUserDataType.theReplacements.localizedDescription).tag(
vChewingLM.ReplacableUserDataType.theReplacements)
Text(vChewingLM.ReplacableUserDataType.theAssociates.localizedDescription).tag(
vChewingLM.ReplacableUserDataType.theAssociates)
Text(vChewingLM.ReplacableUserDataType.theSymbols.localizedDescription).tag(
vChewingLM.ReplacableUserDataType.theSymbols)
}
.labelsHidden()
Button("Reload") {
DispatchQueue.main.async { update() }
}.disabled(selInputMode == .imeModeNULL || isLoading)
Button("Consolidate") {
consolidate()
}.disabled(selInputMode == .imeModeNULL || isLoading)
if #available(macOS 11.0, *) {
Button("Save") {
DispatchQueue.main.async { saveAndReload() }
}.keyboardShortcut("s", modifiers: [.command])
.disabled(isSaved || delegate == nil)
} else {
Button("Save") {
DispatchQueue.main.async { saveAndReload() }
}.disabled(isSaved || delegate == nil)
}
Button("...") {
DispatchQueue.main.async {
saveAndReload()
callExternalAppToOpenPhraseFile()
}
}
}
TextEditorEX(text: $txtContent.onChange { isSaved = false })
.disabled(selInputMode == .imeModeNULL || isLoading)
.frame(minWidth: 320, minHeight: 240)
.backport.onChange(of: fileChangeIndicator.id) { _ in
if Self.autoReloadExternalModifications { update() }
}
VStack(spacing: 4) {
if selUserDataType != .theAssociates {
HStack {
TextField(lblAddPhraseTag4, text: $txtAddPhraseField4)
}
}
HStack {
TextField(lblAddPhraseTag1, text: $txtAddPhraseField1)
TextField(lblAddPhraseTag2, text: $txtAddPhraseField2)
if selUserDataType == .thePhrases {
TextField(
lblAddPhraseTag3,
text: $txtAddPhraseField3.onChange {
guard let weightVal = Double(txtAddPhraseField3) else { return }
if weightVal > 0 { txtAddPhraseField3 = "" }
}
)
}
Button(UITerms.AddPhrases.locAdd.localized.0) {
DispatchQueue.main.async { insertEntry() }
}.disabled(txtAddPhraseField1.isEmpty || txtAddPhraseField2.isEmpty)
}
}.disabled(selInputMode == Shared.InputMode.imeModeNULL || isLoading)
HStack {
if #available(macOS 12, *) {
Toggle(
LocalizedStringKey("This editor only: Auto-reload modifications happened outside of this editor"),
isOn: $selAutoReloadExternalModifications.onChange {
Self.autoReloadExternalModifications = selAutoReloadExternalModifications
}
)
.controlSize(.small)
} else {
Text("Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations.")
.font(.system(size: 11.0)).foregroundColor(.secondary)
}
Spacer()
}
}.onDisappear {
selInputMode = .imeModeNULL
selUserDataType = .thePhrases
txtContent = NSLocalizedString("Please select Simplified / Traditional Chinese mode above.", comment: "")
redrawTrigger.toggle()
}.onAppear {
guard let delegate = delegate else { return }
selInputMode = delegate.currentInputMode
update()
}
}
}
@available(macOS 10.15, *)
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
VwrPhraseEditorUI()
}
}
extension vChewingLM.ReplacableUserDataType {
public var localizedDescription: String { NSLocalizedString(rawValue, comment: "") }
}
private enum UITerms {
fileprivate enum AddPhrases: String {
case locPhrase = "Phrase"
case locReadingOrStroke = "Reading/Stroke"
case locWeight = "Weight"
case locComment = "Comment"
case locReplaceTo = "Replace to"
case locAdd = "Add"
case locInitial = "Initial"
var localized: (String, String) {
if self == .locAdd {
return loc.contains("zh") ? ("添入", "") : loc.contains("ja") ? ("記入", "") : ("Add", "")
}
let rawArray = NSLocalizedString(self.rawValue, comment: "").components(separatedBy: " ")
if rawArray.isEmpty { return ("N/A", "N/A") }
let val1: String = rawArray[0]
let val2: String = (rawArray.count >= 2) ? rawArray[1] : ""
return (val1, val2)
}
}
}

View File

@ -1,4 +1,24 @@
"vChewing" = "vChewing"; "vChewing" = "vChewing";
"Initial" = "Initial";
"Phrase" = "Phrase";
"Reading/Stroke" = "Reading/Stroke";
"Weight" = "Weight";
"Comment" = "Comment";
"Replace to" = "Replace to";
"Save" = "Save";
"Phrase Editor" = "Phrase Editor";
"thePhrases" = "Phrases";
"theFilter" = "Filter";
"theReplacements" = "Replacements";
"theAssociates" = "Associates";
"theSymbols" = "Symbols";
"Please select…" = "Please select…";
"Loading…" = "Loading…";
"Consolidate" = "Consolidate";
"Reload" = "Reload";
"Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations." = "Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations.";
"This editor only: Auto-reload modifications happened outside of this editor" = "This editor only: Auto-reload modifications happened outside of this editor";
"Please select Simplified / Traditional Chinese mode above." = "Please select Simplified / Traditional Chinese mode above.";
"⚠︎ Failed from boosting a candidate." = "⚠︎ Failed from boosting a candidate."; "⚠︎ Failed from boosting a candidate." = "⚠︎ Failed from boosting a candidate.";
"⚠︎ Failed from nerfing a candidate." = "⚠︎ Failed from nerfing a candidate."; "⚠︎ Failed from nerfing a candidate." = "⚠︎ Failed from nerfing a candidate.";
"⚠︎ Failed from filtering a candidate." = "⚠︎ Failed from filtering a candidate."; "⚠︎ Failed from filtering a candidate." = "⚠︎ Failed from filtering a candidate.";

View File

@ -1,4 +1,24 @@
"vChewing" = "vChewing"; "vChewing" = "vChewing";
"Initial" = "Initial";
"Phrase" = "Phrase";
"Reading/Stroke" = "Reading/Stroke";
"Weight" = "Weight";
"Comment" = "Comment";
"Replace to" = "Replace to";
"Save" = "Save";
"Phrase Editor" = "Phrase Editor";
"thePhrases" = "Phrases";
"theFilter" = "Filter";
"theReplacements" = "Replacements";
"theAssociates" = "Associates";
"theSymbols" = "Symbols";
"Please select…" = "Please select…";
"Loading…" = "Loading…";
"Consolidate" = "Consolidate";
"Reload" = "Reload";
"Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations." = "Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations.";
"This editor only: Auto-reload modifications happened outside of this editor" = "This editor only: Auto-reload modifications happened outside of this editor";
"Please select Simplified / Traditional Chinese mode above." = "Please select Simplified / Traditional Chinese mode above.";
"⚠︎ Failed from boosting a candidate." = "⚠︎ Failed from boosting a candidate."; "⚠︎ Failed from boosting a candidate." = "⚠︎ Failed from boosting a candidate.";
"⚠︎ Failed from nerfing a candidate." = "⚠︎ Failed from nerfing a candidate."; "⚠︎ Failed from nerfing a candidate." = "⚠︎ Failed from nerfing a candidate.";
"⚠︎ Failed from filtering a candidate." = "⚠︎ Failed from filtering a candidate."; "⚠︎ Failed from filtering a candidate." = "⚠︎ Failed from filtering a candidate.";

View File

@ -1,4 +1,24 @@
"vChewing" = "威注音入力アプリ"; "vChewing" = "威注音入力アプリ";
"Initial" = "頭文字";
"Phrase" = "語彙";
"Reading/Stroke" = "音読/筆画";
"Weight" = "優先度";
"Comment" = "メモ";
"Replace to" = "単語 →";
"Save" = "セーブ";
"Phrase Editor" = "辞書編集";
"thePhrases" = "ユーザー辞書";
"theFilter" = "排除リスト";
"theReplacements" = "言葉置換";
"theAssociates" = "連想語彙";
"theSymbols" = "絵文字&符号";
"Please select…" = "お選びを…";
"Loading…" = "読み込む中…";
"Consolidate" = "整理";
"Reload" = "再読込";
"Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations." = "システム API 制限のため、一部の機能は macOS 10.15 と macOS 11 で提供できません。";
"This editor only: Auto-reload modifications happened outside of this editor" = "このエディターの外部からの編集結果をこのエディターに自動的に読み込む";
"Please select Simplified / Traditional Chinese mode above." = "まずは上記のメニューで簡体/繁体中国語モードをお選びください。";
"⚠︎ Failed from boosting a candidate." = "⚠︎ 指定された文字候補の順位は最優先にできませんでした。"; "⚠︎ Failed from boosting a candidate." = "⚠︎ 指定された文字候補の順位は最優先にできませんでした。";
"⚠︎ Failed from nerfing a candidate." = "⚠︎ 指定された文字候補の優先順位を下げることに失敗ししました。"; "⚠︎ Failed from nerfing a candidate." = "⚠︎ 指定された文字候補の優先順位を下げることに失敗ししました。";
"⚠︎ Failed from filtering a candidate." = "⚠︎ 指定された文字候補は排除表に登録できませんでした。"; "⚠︎ Failed from filtering a candidate." = "⚠︎ 指定された文字候補は排除表に登録できませんでした。";

View File

@ -1,4 +1,24 @@
"vChewing" = "威注音输入法"; "vChewing" = "威注音输入法";
"Initial" = "首字";
"Phrase" = "词语";
"Reading/Stroke" = "读音/字根";
"Weight" = "权重";
"Comment" = "注释";
"Replace to" = "置换 为";
"Save" = "存档";
"Phrase Editor" = "语汇编辑器";
"thePhrases" = "自订语汇";
"theFilter" = "滤除清单";
"theReplacements" = "语汇置换";
"theAssociates" = "联想字词";
"theSymbols" = "绘文字符号";
"Please select…" = "请选择…";
"Loading…" = "正在载入…";
"Consolidate" = "整理";
"Reload" = "重新载入";
"Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations." = "因系统 API 限制,个别功能无法对 macOS 10.15 和 macOS 11 提供。";
"This editor only: Auto-reload modifications happened outside of this editor" = "仅限该编辑器:自动读入来自该编辑器外部的档案内容修改";
"Please select Simplified / Traditional Chinese mode above." = "请先借由上方选单选择简繁模式。";
"⚠︎ Failed from boosting a candidate." = "⚠︎ 候选字词提权失败。"; "⚠︎ Failed from boosting a candidate." = "⚠︎ 候选字词提权失败。";
"⚠︎ Failed from nerfing a candidate." = "⚠︎ 候选字词降权失败。"; "⚠︎ Failed from nerfing a candidate." = "⚠︎ 候选字词降权失败。";
"⚠︎ Failed from filtering a candidate." = "⚠︎ 候选字词滤除失败。"; "⚠︎ Failed from filtering a candidate." = "⚠︎ 候选字词滤除失败。";

View File

@ -1,4 +1,24 @@
"vChewing" = "威注音輸入法"; "vChewing" = "威注音輸入法";
"Initial" = "首字";
"Phrase" = "詞語";
"Reading/Stroke" = "讀音/字根";
"Weight" = "權重";
"Comment" = "註釋";
"Replace to" = "置換 為";
"Save" = "存檔";
"Phrase Editor" = "語彙編輯器";
"thePhrases" = "自訂語彙";
"theFilter" = "濾除清單";
"theReplacements" = "語彙置換";
"theAssociates" = "聯想字詞";
"theSymbols" = "繪文字符號";
"Please select…" = "請選擇…";
"Loading…" = "正在載入…";
"Consolidate" = "整理";
"Reload" = "重新載入";
"Some features are unavailable for macOS 10.15 and macOS 11 due to API limitations." = "因系統 API 限制,個別功能無法對 macOS 10.15 和 macOS 11 提供。";
"This editor only: Auto-reload modifications happened outside of this editor" = "僅限該編輯器:自動讀入來自該編輯器外部的檔案內容修改";
"Please select Simplified / Traditional Chinese mode above." = "請先藉由上方選單選擇繁簡模式。";
"⚠︎ Failed from boosting a candidate." = "⚠︎ 候選字詞提權失敗。"; "⚠︎ Failed from boosting a candidate." = "⚠︎ 候選字詞提權失敗。";
"⚠︎ Failed from nerfing a candidate." = "⚠︎ 候選字詞降權失敗。"; "⚠︎ Failed from nerfing a candidate." = "⚠︎ 候選字詞降權失敗。";
"⚠︎ Failed from filtering a candidate." = "⚠︎ 候選字詞濾除失敗。"; "⚠︎ Failed from filtering a candidate." = "⚠︎ 候選字詞濾除失敗。";

View File

@ -29,6 +29,7 @@
5B660A8628F64A8800E5E4F6 /* SymbolMenuDefaultData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B660A8528F64A8800E5E4F6 /* SymbolMenuDefaultData.swift */; }; 5B660A8628F64A8800E5E4F6 /* SymbolMenuDefaultData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B660A8528F64A8800E5E4F6 /* SymbolMenuDefaultData.swift */; };
5B6C141228A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6C141128A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift */; }; 5B6C141228A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6C141128A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift */; };
5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; }; 5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; };
5B765F09293A253C00122315 /* PhraseEditorUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5B765F08293A253C00122315 /* PhraseEditorUI */; };
5B782EC4280C243C007276DE /* InputHandler_HandleCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B782EC3280C243C007276DE /* InputHandler_HandleCandidate.swift */; }; 5B782EC4280C243C007276DE /* InputHandler_HandleCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B782EC3280C243C007276DE /* InputHandler_HandleCandidate.swift */; };
5B78EE0D28A562B4009456C1 /* VwrPrefPaneDevZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B78EE0C28A562B4009456C1 /* VwrPrefPaneDevZone.swift */; }; 5B78EE0D28A562B4009456C1 /* VwrPrefPaneDevZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B78EE0C28A562B4009456C1 /* VwrPrefPaneDevZone.swift */; };
5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */; }; 5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */; };
@ -236,6 +237,7 @@
5B6C141128A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionCtl_HandleEvent.swift; sourceTree = "<group>"; }; 5B6C141128A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionCtl_HandleEvent.swift; sourceTree = "<group>"; };
5B73FB5427B2BD6900E9BF49 /* PhraseEditor-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "PhraseEditor-Info.plist"; path = "UserPhraseEditor/PhraseEditor-Info.plist"; sourceTree = SOURCE_ROOT; }; 5B73FB5427B2BD6900E9BF49 /* PhraseEditor-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "PhraseEditor-Info.plist"; path = "UserPhraseEditor/PhraseEditor-Info.plist"; sourceTree = SOURCE_ROOT; };
5B73FB5F27B2BE1300E9BF49 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 5B73FB5F27B2BE1300E9BF49 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5B765F07293A250000122315 /* vChewing_PhraseEditorUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_PhraseEditorUI; path = Packages/vChewing_PhraseEditorUI; sourceTree = "<group>"; };
5B782EC3280C243C007276DE /* InputHandler_HandleCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputHandler_HandleCandidate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; }; 5B782EC3280C243C007276DE /* InputHandler_HandleCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputHandler_HandleCandidate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B78EE0C28A562B4009456C1 /* VwrPrefPaneDevZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VwrPrefPaneDevZone.swift; sourceTree = "<group>"; }; 5B78EE0C28A562B4009456C1 /* VwrPrefPaneDevZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VwrPrefPaneDevZone.swift; sourceTree = "<group>"; };
5B7BC4AF27AFFBE800F66C24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPrefWindow.xib; sourceTree = "<group>"; }; 5B7BC4AF27AFFBE800F66C24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPrefWindow.xib; sourceTree = "<group>"; };
@ -385,6 +387,7 @@
5B98114828D6198700CBC605 /* PinyinPhonaConverter in Frameworks */, 5B98114828D6198700CBC605 /* PinyinPhonaConverter in Frameworks */,
5BFC63CF28D4ACA3004A77B7 /* LangModelAssembly in Frameworks */, 5BFC63CF28D4ACA3004A77B7 /* LangModelAssembly in Frameworks */,
5BC5E02128DDEFE00094E427 /* TooltipUI in Frameworks */, 5BC5E02128DDEFE00094E427 /* TooltipUI in Frameworks */,
5B765F09293A253C00122315 /* PhraseEditorUI in Frameworks */,
5BDB7A3928D4824A001AC277 /* BookmarkManager in Frameworks */, 5BDB7A3928D4824A001AC277 /* BookmarkManager in Frameworks */,
5B5C8ED828FC0EA9002C93A5 /* SSPreferences in Frameworks */, 5B5C8ED828FC0EA9002C93A5 /* SSPreferences in Frameworks */,
5B5A603028E81CC50001AE8D /* SwiftUIBackports in Frameworks */, 5B5A603028E81CC50001AE8D /* SwiftUIBackports in Frameworks */,
@ -622,6 +625,7 @@
5BFC63CD28D4AC98004A77B7 /* vChewing_LangModelAssembly */, 5BFC63CD28D4AC98004A77B7 /* vChewing_LangModelAssembly */,
5BDB7A3328D47587001AC277 /* vChewing_Megrez */, 5BDB7A3328D47587001AC277 /* vChewing_Megrez */,
5BC5E01C28DDE4270094E427 /* vChewing_NotifierUI */, 5BC5E01C28DDE4270094E427 /* vChewing_NotifierUI */,
5B765F07293A250000122315 /* vChewing_PhraseEditorUI */,
5B98114628D6198000CBC605 /* vChewing_PinyinPhonaConverter */, 5B98114628D6198000CBC605 /* vChewing_PinyinPhonaConverter */,
5BC5E02228DE07250094E427 /* vChewing_PopupCompositionBuffer */, 5BC5E02228DE07250094E427 /* vChewing_PopupCompositionBuffer */,
5B963C9E28D5C14600DCEE88 /* vChewing_Shared */, 5B963C9E28D5C14600DCEE88 /* vChewing_Shared */,
@ -864,6 +868,7 @@
5BA8C30228DF0360004C5CC4 /* CandidateWindow */, 5BA8C30228DF0360004C5CC4 /* CandidateWindow */,
5B5A602F28E81CC50001AE8D /* SwiftUIBackports */, 5B5A602F28E81CC50001AE8D /* SwiftUIBackports */,
5B5C8ED728FC0EA9002C93A5 /* SSPreferences */, 5B5C8ED728FC0EA9002C93A5 /* SSPreferences */,
5B765F08293A253C00122315 /* PhraseEditorUI */,
); );
productName = vChewing; productName = vChewing;
productReference = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */; productReference = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */;
@ -2034,6 +2039,10 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = SSPreferences; productName = SSPreferences;
}; };
5B765F08293A253C00122315 /* PhraseEditorUI */ = {
isa = XCSwiftPackageProductDependency;
productName = PhraseEditorUI;
};
5B963C9C28D5BFB800DCEE88 /* CocoaExtension */ = { 5B963C9C28D5BFB800DCEE88 /* CocoaExtension */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = CocoaExtension; productName = CocoaExtension;