diff --git a/McBopomofo.xcodeproj/project.pbxproj b/McBopomofo.xcodeproj/project.pbxproj index c2f34dc4..19efaa09 100644 --- a/McBopomofo.xcodeproj/project.pbxproj +++ b/McBopomofo.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 6A6ED16C2797650A0012872E /* template-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A6ED1652797650A0012872E /* template-data.txt */; }; 6A6ED16D2797650A0012872E /* template-exclude-phrases-plain-bpmf.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A6ED1672797650A0012872E /* template-exclude-phrases-plain-bpmf.txt */; }; 6A6ED16E2797650A0012872E /* template-exclude-phrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A6ED1692797650A0012872E /* template-exclude-phrases.txt */; }; + 6A7C450C2CC571D00076AECA /* template-data-plain-bpmf.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A7C450A2CC571D00076AECA /* template-data-plain-bpmf.txt */; }; 6ACA41FA15FC1D9000935EF6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41EA15FC1D9000935EF6 /* InfoPlist.strings */; }; 6ACA41FB15FC1D9000935EF6 /* License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41EC15FC1D9000935EF6 /* License.rtf */; }; 6ACA41FC15FC1D9000935EF6 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41EE15FC1D9000935EF6 /* Localizable.strings */; }; @@ -139,6 +140,8 @@ 6A6ED170279765140012872E /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text; name = "zh-Hant"; path = "zh-Hant.lproj/template-exclude-phrases-plain-bpmf.txt"; sourceTree = ""; }; 6A6ED171279765170012872E /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text; name = "zh-Hant"; path = "zh-Hant.lproj/template-exclude-phrases.txt"; sourceTree = ""; }; 6A6ED1722797651A0012872E /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text; name = "zh-Hant"; path = "zh-Hant.lproj/template-phrases-replacement.txt"; sourceTree = ""; }; + 6A7C450B2CC571D00076AECA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text; name = Base; path = "Base.lproj/template-data-plain-bpmf.txt"; sourceTree = ""; }; + 6A7C450D2CC571E10076AECA /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text; name = "zh-Hant"; path = "zh-Hant.lproj/template-data-plain-bpmf.txt"; sourceTree = ""; }; 6A93050C279877FF00D370DA /* McBopomofoInstaller-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "McBopomofoInstaller-Bridging-Header.h"; sourceTree = ""; }; 6ACA41CB15FC1D7500935EF6 /* McBopomofoInstaller.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = McBopomofoInstaller.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6ACA41EB15FC1D9000935EF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -412,6 +415,7 @@ isa = PBXGroup; children = ( 6A6ED1652797650A0012872E /* template-data.txt */, + 6A7C450A2CC571D00076AECA /* template-data-plain-bpmf.txt */, 6A6ED1672797650A0012872E /* template-exclude-phrases-plain-bpmf.txt */, 6A6ED1692797650A0012872E /* template-exclude-phrases.txt */, 6A6ED1632797650A0012872E /* template-phrases-replacement.txt */, @@ -632,6 +636,7 @@ 6AFF97F2253B299E007F1C49 /* NonModalAlertWindowController.xib in Resources */, D4EE675A2B39968900F062DE /* dictionary_service.json in Resources */, 6AE210B215FC63CC003659FE /* PlainBopomofo.tiff in Resources */, + 6A7C450C2CC571D00076AECA /* template-data-plain-bpmf.txt in Resources */, D4F0BBE7279B14C20071253C /* Credits.rtf in Resources */, D476CB492827DB6300F48552 /* add-phrase-hook.sh in Resources */, 6A6ED16C2797650A0012872E /* template-data.txt in Resources */, @@ -825,6 +830,15 @@ name = "template-exclude-phrases.txt"; sourceTree = ""; }; + 6A7C450A2CC571D00076AECA /* template-data-plain-bpmf.txt */ = { + isa = PBXVariantGroup; + children = ( + 6A7C450B2CC571D00076AECA /* Base */, + 6A7C450D2CC571E10076AECA /* zh-Hant */, + ); + name = "template-data-plain-bpmf.txt"; + sourceTree = ""; + }; 6ACA41EA15FC1D9000935EF6 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( diff --git a/README.markdown b/README.markdown index 1b672247..2f4234ea 100644 --- a/README.markdown +++ b/README.markdown @@ -2,10 +2,10 @@ ## 系統需求 -小麥注音輸入法可以在 macOS 10.13 以上版本運作。如果您要自行編譯小麥注音輸入法,或參與開發,您需要: +小麥注音輸入法可以在 macOS 10.15 以上版本運作。如果您要自行編譯小麥注音輸入法,或參與開發,您需要: -- macOS 13.6 以上版本 -- Xcode 15.1 以上版本 +- macOS 14.7 以上版本 +- Xcode 15.3 以上版本 - Python 3.9 (可使用 Xcode 安裝後內附的,或是使用 homebrew 等方式安裝) ## 開發流程 diff --git a/Source/AppDelegate.swift b/Source/AppDelegate.swift index 8f5d6e17..b826845d 100644 --- a/Source/AppDelegate.swift +++ b/Source/AppDelegate.swift @@ -155,7 +155,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle func updateUserPhrases() { NSLog("updateUserPhrases called \(LanguageModelManager.dataFolderPath)") - LanguageModelManager.loadUserPhrases() + LanguageModelManager.loadUserPhrases(enableForPlainBopomofo: Preferences.EnableUserPhrasesInPlainBopomofo) LanguageModelManager.loadUserPhraseReplacement() fsStreamHelper?.delegate = nil @@ -274,7 +274,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle extension AppDelegate: FSEventStreamHelperDelegate { func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) { DispatchQueue.main.async { - LanguageModelManager.loadUserPhrases() + LanguageModelManager.loadUserPhrases(enableForPlainBopomofo: Preferences.EnableUserPhrasesInPlainBopomofo) LanguageModelManager.loadUserPhraseReplacement() } } @@ -302,6 +302,10 @@ extension AppDelegate { open(userFileAt: LanguageModelManager.userPhrasesDataPathMcBopomofo) } + @objc func openUserPhrasesPlainBopomofo(_ sender: Any?) { + open(userFileAt: LanguageModelManager.userPhrasesDataPathPlainBopomofo) + } + @objc func openExcludedPhrasesPlainBopomofo(_ sender: Any?) { open(userFileAt: LanguageModelManager.excludedPhrasesDataPathPlainBopomofo) } diff --git a/Source/Base.lproj/preferences.xib b/Source/Base.lproj/preferences.xib index 03a638d7..caf0eb0b 100644 --- a/Source/Base.lproj/preferences.xib +++ b/Source/Base.lproj/preferences.xib @@ -28,7 +28,7 @@ - + @@ -52,7 +52,7 @@ - + @@ -108,7 +108,7 @@ - + @@ -187,7 +187,7 @@ - + @@ -462,7 +462,7 @@ when selecting candidats - + @@ -514,7 +514,7 @@ when selecting candidats - + diff --git a/Source/Base.lproj/template-data-plain-bpmf.txt b/Source/Base.lproj/template-data-plain-bpmf.txt new file mode 100644 index 00000000..fe9d4fc5 --- /dev/null +++ b/Source/Base.lproj/template-data-plain-bpmf.txt @@ -0,0 +1,10 @@ +# Custom Characters (for Plain Bopomofo). +# +# See https://github.com/openvanilla/McBopomofo/wiki/使用手冊#手動加詞 for usage. +# +# Add your characters and their respective Bopomofo reading below. +# +# 㵘 ㄇㄢˋ +# +# Any line that starts with "#" is treated as comment. + diff --git a/Source/Engine/McBopomofoLM.cpp b/Source/Engine/McBopomofoLM.cpp index 0bb3107c..f498ae39 100644 --- a/Source/Engine/McBopomofoLM.cpp +++ b/Source/Engine/McBopomofoLM.cpp @@ -56,12 +56,13 @@ void McBopomofoLM::loadAssociatedPhrasesV2(const char* associatedPhrasesPath) { void McBopomofoLM::loadUserPhrases(const char* userPhrasesDataPath, const char* excludedPhrasesDataPath) { + userPhrases_.close(); + excludedPhrases_.close(); + if (userPhrasesDataPath) { - userPhrases_.close(); userPhrases_.open(userPhrasesDataPath); } if (excludedPhrasesDataPath) { - excludedPhrases_.close(); excludedPhrases_.open(excludedPhrasesDataPath); } } diff --git a/Source/InputMethodController.swift b/Source/InputMethodController.swift index dce739bc..000e4580 100644 --- a/Source/InputMethodController.swift +++ b/Source/InputMethodController.swift @@ -86,6 +86,9 @@ class McBopomofoInputMethodController: IMKInputController { menu.addItem(withTitle: NSLocalizedString("User Phrases", comment: ""), action: nil, keyEquivalent: "") if inputMode == .plainBopomofo { + if (Preferences.EnableUserPhrasesInPlainBopomofo) { + menu.addItem(withTitle: NSLocalizedString("Edit User Phrases", comment: ""), action: #selector(openUserPhrasesPlainBopomofo(_:)), keyEquivalent: "") + } menu.addItem(withTitle: NSLocalizedString("Edit Excluded Phrases", comment: ""), action: #selector(openExcludedPhrasesPlainBopomofo(_:)), keyEquivalent: "") } else { menu.addItem(withTitle: NSLocalizedString("Edit User Phrases", comment: ""), action: #selector(openUserPhrases(_:)), keyEquivalent: "") @@ -234,6 +237,10 @@ class McBopomofoInputMethodController: IMKInputController { (NSApp.delegate as? AppDelegate)?.openUserPhrases(sender) } + @objc func openUserPhrasesPlainBopomofo(_ sender: Any?) { + (NSApp.delegate as? AppDelegate)?.openUserPhrasesPlainBopomofo(sender) + } + @objc func openExcludedPhrasesPlainBopomofo(_ sender: Any?) { (NSApp.delegate as? AppDelegate)?.openExcludedPhrasesPlainBopomofo(sender) } @@ -247,7 +254,7 @@ class McBopomofoInputMethodController: IMKInputController { } @objc func reloadUserPhrases(_ sender: Any?) { - LanguageModelManager.loadUserPhrases() + LanguageModelManager.loadUserPhrases(enableForPlainBopomofo: Preferences.EnableUserPhrasesInPlainBopomofo) LanguageModelManager.loadUserPhraseReplacement() } diff --git a/Source/LanguageModelManager.h b/Source/LanguageModelManager.h index 72790116..7c276578 100644 --- a/Source/LanguageModelManager.h +++ b/Source/LanguageModelManager.h @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN @interface LanguageModelManager : NSObject + (void)loadDataModel:(InputMode)mode; -+ (void)loadUserPhrases; ++ (void)loadUserPhrasesWithPlainBopomofoEnabled:(BOOL)userPhraseForPlainBopomofo NS_SWIFT_NAME(loadUserPhrases(enableForPlainBopomofo:)); + (void)loadUserPhraseReplacement; + (void)setupDataModelValueConverter; + (BOOL)checkIfUserLanguageModelFilesExist; @@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN @property (class, readonly, nonatomic) NSString *dataFolderPath; @property (class, readonly, nonatomic) NSString *userPhrasesDataPathMcBopomofo; +@property (class, readonly, nonatomic) NSString *userPhrasesDataPathPlainBopomofo; @property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathMcBopomofo; @property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathPlainBopomofo; @property (class, readonly, nonatomic) NSString *phraseReplacementDataPathMcBopomofo; diff --git a/Source/LanguageModelManager.mm b/Source/LanguageModelManager.mm index cf79d40a..ac6019a2 100644 --- a/Source/LanguageModelManager.mm +++ b/Source/LanguageModelManager.mm @@ -35,6 +35,7 @@ static McBopomofo::UserOverrideModel gUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife); static NSString *const kUserDataTemplateName = @"template-data"; +static NSString *const kUserDataPlainBopomofoTemplateName = @"template-data-plain-bpmf"; static NSString *const kExcludedPhrasesMcBopomofoTemplateName = @"template-exclude-phrases"; static NSString *const kExcludedPhrasesPlainBopomofoTemplateName = @"template-exclude-phrases-plain-bpmf"; static NSString *const kPhraseReplacementTemplateName = @"template-phrases-replacement"; @@ -94,10 +95,12 @@ + (void)loadDataModel:(InputMode)mode } } -+ (void)loadUserPhrases ++ (void)loadUserPhrasesWithPlainBopomofoEnabled:(BOOL)userPhraseForPlainBopomofo { gLanguageModelMcBopomofo.loadUserPhrases([self userPhrasesDataPathMcBopomofo].UTF8String, [self excludedPhrasesDataPathMcBopomofo].UTF8String); - gLanguageModelPlainBopomofo.loadUserPhrases(NULL, [self excludedPhrasesDataPathPlainBopomofo].UTF8String); + gLanguageModelPlainBopomofo.loadUserPhrases(userPhraseForPlainBopomofo ? + [self userPhrasesDataPathPlainBopomofo].UTF8String : NULL, + [self excludedPhrasesDataPathPlainBopomofo].UTF8String); } + (void)loadUserPhraseReplacement @@ -185,6 +188,9 @@ + (BOOL)checkIfUserLanguageModelFilesExist if (![self ensureFileExists:[self userPhrasesDataPathMcBopomofo] populateWithTemplate:kUserDataTemplateName extension:kTemplateExtension]) { return NO; } + if (![self ensureFileExists:[self userPhrasesDataPathPlainBopomofo] populateWithTemplate:kUserDataPlainBopomofoTemplateName extension:kTemplateExtension]) { + return NO; + } if (![self ensureFileExists:[self excludedPhrasesDataPathMcBopomofo] populateWithTemplate:kExcludedPhrasesMcBopomofoTemplateName extension:kTemplateExtension]) { return NO; } @@ -273,6 +279,11 @@ + (NSString *)userPhrasesDataPathMcBopomofo return [[self dataFolderPath] stringByAppendingPathComponent:@"data.txt"]; } ++ (NSString *)userPhrasesDataPathPlainBopomofo +{ + return [[self dataFolderPath] stringByAppendingPathComponent:@"data-plain-bpmf.txt"]; +} + + (NSString *)excludedPhrasesDataPathMcBopomofo { return [[self dataFolderPath] stringByAppendingPathComponent:@"exclude-phrases.txt"]; diff --git a/Source/Preferences.swift b/Source/Preferences.swift index d096a70a..3fb94b98 100644 --- a/Source/Preferences.swift +++ b/Source/Preferences.swift @@ -70,6 +70,8 @@ private let kBig5InputEnabledKey = "Big5InputEnabled" // Need to be populated to true by default upon first start, so the key is not private. let kBeepUponInputErrorKey = "BeepUponInputError" +private let kEnableUserPhrasesInPlainBopomofo = "EnableUserPhrasesInPlainBopomofo" + // MARK: Property wrappers @propertyWrapper @@ -488,3 +490,8 @@ extension Preferences { @UserDefault(key: kBeepUponInputErrorKey, defaultValue: true) @objc static var BeepUponInputError: Bool } + +extension Preferences { + @UserDefault(key: kEnableUserPhrasesInPlainBopomofo, defaultValue: false) + @objc static var EnableUserPhrasesInPlainBopomofo: Bool +} diff --git a/Source/zh-Hant.lproj/preferences.xib b/Source/zh-Hant.lproj/preferences.xib index 200f9987..9edc4720 100644 --- a/Source/zh-Hant.lproj/preferences.xib +++ b/Source/zh-Hant.lproj/preferences.xib @@ -28,7 +28,7 @@ - + @@ -40,11 +40,11 @@ - - + + - + @@ -63,18 +63,18 @@ - + - - + + - + @@ -82,7 +82,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -98,7 +98,7 @@ - + @@ -130,11 +130,11 @@ - - + + - + @@ -153,7 +153,7 @@ - - + + @@ -179,26 +179,25 @@ - + - - + @@ -208,12 +207,11 @@ - - + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -292,20 +262,17 @@ + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + + + + + - - - - + + + + + + - + - + @@ -425,7 +424,7 @@ - + @@ -433,18 +432,18 @@ - + - - + + - + @@ -459,7 +458,7 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -494,7 +494,7 @@ - + @@ -502,10 +502,10 @@ - + - + @@ -532,7 +532,7 @@ - + @@ -593,7 +593,7 @@ - +