From b627e8e3b67d692f6bcc1ec5d7dd4a9e9eb4d519 Mon Sep 17 00:00:00 2001 From: zonble Date: Sat, 15 Jan 2022 20:12:13 +0800 Subject: [PATCH] Adds an option to let users to choose Chinse conversion style. Option 0: converts the output. Option 1: converts the models. --- Source/AppDelegate.swift | 1 + Source/Base.lproj/preferences.xib | 83 ++++++++++++++++++++-------- Source/Engine/McBopomofoLM.cpp | 32 ++++++++++- Source/Engine/McBopomofoLM.h | 6 ++ Source/InputMethodController.mm | 25 +++++---- Source/LanguageModelManager.h | 1 + Source/LanguageModelManager.mm | 29 ++++++++++ Source/McBopomofo-Bridging-Header.h | 1 + Source/Preferences.swift | 46 ++++++++++++--- Source/zh-Hant.lproj/preferences.xib | 83 ++++++++++++++++++++-------- 10 files changed, 238 insertions(+), 69 deletions(-) diff --git a/Source/AppDelegate.swift b/Source/AppDelegate.swift index f93bf8b2..f8d348fb 100644 --- a/Source/AppDelegate.swift +++ b/Source/AppDelegate.swift @@ -51,6 +51,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle private var updateNextStepURL: URL? func applicationDidFinishLaunching(_ notification: Notification) { + LanguageModelManager.setupDataModelValueConverter() LanguageModelManager.loadDataModels() LanguageModelManager.loadUserPhrases() LanguageModelManager.loadUserPhraseReplacement() diff --git a/Source/Base.lproj/preferences.xib b/Source/Base.lproj/preferences.xib index 451d8d39..25ee9a38 100644 --- a/Source/Base.lproj/preferences.xib +++ b/Source/Base.lproj/preferences.xib @@ -19,14 +19,14 @@ - + - + - + @@ -35,7 +35,7 @@ - + @@ -47,7 +47,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -84,7 +84,7 @@ - + @@ -93,7 +93,7 @@ - + @@ -114,7 +114,7 @@ - + @@ -134,7 +134,7 @@ - + @@ -143,7 +143,7 @@ - + @@ -152,7 +152,7 @@ - + @@ -161,7 +161,7 @@ - + @@ -187,7 +187,7 @@ - + @@ -212,8 +212,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -239,7 +274,7 @@ - + @@ -261,12 +296,8 @@ - - - - + + + + - + diff --git a/Source/Engine/McBopomofoLM.cpp b/Source/Engine/McBopomofoLM.cpp index 3fba9fc9..1e235447 100644 --- a/Source/Engine/McBopomofoLM.cpp +++ b/Source/Engine/McBopomofoLM.cpp @@ -121,20 +121,46 @@ bool McBopomofoLM::phraseReplacementEnabled() return m_phraseReplacementEnabled; } +void McBopomofoLM::setExternalConverterEnabled(bool enabled) +{ + m_externalConverterEnabled = enabled; +} + +bool McBopomofoLM::externalConverterEnabled() +{ + return m_externalConverterEnabled; +} + +void McBopomofoLM::setExternalConvrter(std::function externalConverter) +{ + m_externalConverter = externalConverter; +} + const vector McBopomofoLM::filterAndTransformUnigrams(vector unigrams, const unordered_set& excludedValues, unordered_set& insertedValues) { vector results; for (auto&& unigram : unigrams) { - string value = unigram.keyValue.value; + // excludedValues filters out the unigrams with the original value. + // insertedValues filters out the ones with the converted value + string originalValue = unigram.keyValue.value; + if (excludedValues.find(originalValue) != excludedValues.end()) { + continue; + } + + string value = originalValue; if (m_phraseReplacementEnabled) { string replacement = m_phraseReplacement.valueForKey(value); if (replacement != "") { value = replacement; - unigram.keyValue.value = value; } } - if (excludedValues.find(value) == excludedValues.end() && insertedValues.find(value) == insertedValues.end()) { + if (m_externalConverterEnabled && m_externalConverter) { + string replacement = m_externalConverter(value); + value = replacement; + } + unigram.keyValue.value = value; + if (insertedValues.find(value) == insertedValues.end()) { results.push_back(unigram); insertedValues.insert(value); } diff --git a/Source/Engine/McBopomofoLM.h b/Source/Engine/McBopomofoLM.h index 00dbc360..63ae7361 100644 --- a/Source/Engine/McBopomofoLM.h +++ b/Source/Engine/McBopomofoLM.h @@ -50,6 +50,10 @@ public: void setPhraseReplacementEnabled(bool enabled); bool phraseReplacementEnabled(); + void setExternalConverterEnabled(bool enabled); + bool externalConverterEnabled(); + void setExternalConvrter(std::function externalConverter); + protected: const vector filterAndTransformUnigrams(vector unigrams, const std::unordered_set& excludedValues, @@ -60,6 +64,8 @@ protected: UserPhrasesLM m_excludedPhrases; PhraseReplacementMap m_phraseReplacement; bool m_phraseReplacementEnabled; + bool m_externalConverterEnabled; + std::function m_externalConverter; }; }; diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm index 762e7665..16963ebc 100644 --- a/Source/InputMethodController.mm +++ b/Source/InputMethodController.mm @@ -243,6 +243,8 @@ static double FindHighestScore(const vector& nodes, double epsilon) Preferences.keyboardLayout = KeyboardLayoutStandard; } + _languageModel->setExternalConverterEnabled(Preferences.chineseConversionStyle == 1); + [(AppDelegate *)[NSApp delegate] checkForUpdate]; } @@ -275,12 +277,14 @@ static double FindHighestScore(const vector& nodes, double epsilon) if ([value isKindOfClass:[NSString class]] && [value isEqual:kPlainBopomofoModeIdentifier]) { newInputMode = kPlainBopomofoModeIdentifier; newLanguageModel = [LanguageModelManager languageModelPlainBopomofo]; + newLanguageModel->setPhraseReplacementEnabled(false); } else { newInputMode = kBopomofoModeIdentifier; newLanguageModel = [LanguageModelManager languageModelMcBopomofo]; newLanguageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled); } + newLanguageModel->setExternalConverterEnabled(Preferences.chineseConversionStyle == 1); // Only apply the changes if the value is changed if (![_inputMode isEqualToString:newInputMode]) { @@ -312,8 +316,16 @@ static double FindHighestScore(const vector& nodes, double epsilon) #pragma mark - IMKServerInput protocol methods -- (NSString *)_convertToSimplifiedChinese:(NSString *)text +- (NSString *)_convertToSimplifiedChineseIfRequired:(NSString *)text { + if (!Preferences.chineseConversionEnabled) { + return text; + } + + if (Preferences.chineseConversionStyle == 1) { + return text; + } + if (Preferences.chineneConversionEngine == 1) { return [VXHanConvert convertToSimplifiedFrom:text]; } @@ -333,11 +345,7 @@ static double FindHighestScore(const vector& nodes, double epsilon) } // Chinese conversion. - NSString *buffer = _composingBuffer; - - if (Preferences.chineseConversionEnabled) { - buffer = [self _convertToSimplifiedChinese:_composingBuffer]; - } + NSString *buffer = [self _convertToSimplifiedChineseIfRequired:_composingBuffer]; // commit the text, clear the state [client insertText:buffer replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; @@ -483,10 +491,7 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; } NodeAnchor &anchor = _walkedNodes[0]; NSString *popedText = [NSString stringWithUTF8String:anchor.node->currentKeyValue().value.c_str()]; // Chinese conversion. - BOOL chineseConversionEnabled = Preferences.chineseConversionEnabled; - if (chineseConversionEnabled) { - popedText = [self _convertToSimplifiedChinese:popedText]; - } + popedText = [self _convertToSimplifiedChineseIfRequired:popedText]; [client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; _builder->removeHeadReadings(anchor.spanningLength); } diff --git a/Source/LanguageModelManager.h b/Source/LanguageModelManager.h index 6a82c47a..ce28eaf5 100644 --- a/Source/LanguageModelManager.h +++ b/Source/LanguageModelManager.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN + (void)loadDataModels; + (void)loadUserPhrases; + (void)loadUserPhraseReplacement; ++ (void)setupDataModelValueConverter; + (BOOL)checkIfUserLanguageModelFilesExist; + (BOOL)writeUserPhrase:(NSString *)userPhrase; diff --git a/Source/LanguageModelManager.mm b/Source/LanguageModelManager.mm index 189e2eb6..37fa2897 100644 --- a/Source/LanguageModelManager.mm +++ b/Source/LanguageModelManager.mm @@ -4,6 +4,10 @@ #import #import "OVStringHelper.h" #import "OVUTF8Helper.h" +#import "McBopomofo-Swift.h" + +@import VXHanConvert; +@import OpenCCBridge; using namespace std; using namespace Formosa::Gramambular; @@ -43,6 +47,31 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, McBopomo gLanguageModelMcBopomofo.loadPhraseReplacementMap([[self phraseReplacementDataPathMcBopomofo] UTF8String]); } ++ (void)setupDataModelValueConverter +{ + auto converter = [] (string input) { + if (!Preferences.chineseConversionEnabled) { + return input; + } + + if (Preferences.chineseConversionStyle == 0) { + return input; + } + + NSString *text = [NSString stringWithUTF8String:input.c_str()]; + if (Preferences.chineneConversionEngine == 1) { + text = [VXHanConvert convertToSimplifiedFrom:text]; + } + else { + text = [OpenCCBridge convertToSimplified:text]; + } + return string(text.UTF8String); + }; + + gLanguageModelMcBopomofo.setExternalConvrter(converter); + gLanguageModelPlainBopomofo.setExternalConvrter(converter); +} + + (BOOL)checkIfUserDataFolderExists { NSString *folderPath = [self dataFolderPath]; diff --git a/Source/McBopomofo-Bridging-Header.h b/Source/McBopomofo-Bridging-Header.h index 8310cc67..69a7fc4f 100644 --- a/Source/McBopomofo-Bridging-Header.h +++ b/Source/McBopomofo-Bridging-Header.h @@ -8,4 +8,5 @@ + (void)loadDataModels; + (void)loadUserPhrases; + (void)loadUserPhraseReplacement; ++ (void)setupDataModelValueConverter; @end diff --git a/Source/Preferences.swift b/Source/Preferences.swift index e1f2303c..61ecead0 100644 --- a/Source/Preferences.swift +++ b/Source/Preferences.swift @@ -50,8 +50,9 @@ private let kEscToCleanInputBufferKey = "EscToCleanInputBuffer" private let kCandidateTextFontName = "CandidateTextFontName" private let kCandidateKeyLabelFontName = "CandidateKeyLabelFontName" private let kCandidateKeys = "CandidateKeys" -private let kChineseConversionEngineKey = "ChineseConversionEngine" private let kPhraseReplacementEnabledKey = "PhraseReplacementEnabled" +private let kChineseConversionEngineKey = "ChineseConversionEngine" +private let kChineseConversionStyle = "ChineseConversionStyle" private let kDefaultCandidateListTextSize: CGFloat = 16 private let kMinKeyLabelSize: CGFloat = 10 @@ -217,6 +218,20 @@ struct ComposingKeys { } } +@objc enum ChineseConversionStyle: Int { + case output + case model + + var name: String { + switch (self) { + case .output: + return "output" + case .model: + return "model" + } + } +} + // MARK: - class Preferences: NSObject { @@ -285,13 +300,6 @@ class Preferences: NSObject { kDefaultKeys } - @UserDefault(key: kChineseConversionEngineKey, defaultValue: 0) - @objc static var chineneConversionEngine: Int - - @objc static var chineneConversionEngineName: String? { - return ChineseConversionEngine(rawValue: chineneConversionEngine)?.name - } - @UserDefault(key: kPhraseReplacementEnabledKey, defaultValue: false) @objc static var phraseReplacementEnabled: Bool @@ -300,4 +308,26 @@ class Preferences: NSObject { return phraseReplacementEnabled; } + /// The conversion engine. + /// + /// - 0: OpenCC + /// - 1: VXHanConvert + @UserDefault(key: kChineseConversionEngineKey, defaultValue: 0) + @objc static var chineneConversionEngine: Int + + @objc static var chineneConversionEngineName: String? { + return ChineseConversionEngine(rawValue: chineneConversionEngine)?.name + } + + /// The conversion style. + /// + /// - 0: convert the output + /// - 1: convert the phrase models. + @UserDefault(key: kChineseConversionStyle, defaultValue: 0) + @objc static var chineseConversionStyle: Int + + @objc static var chineseConversionStyleName: String? { + return ChineseConversionStyle(rawValue: chineseConversionStyle)?.name + } + } diff --git a/Source/zh-Hant.lproj/preferences.xib b/Source/zh-Hant.lproj/preferences.xib index 6cd9981c..3aad70ae 100644 --- a/Source/zh-Hant.lproj/preferences.xib +++ b/Source/zh-Hant.lproj/preferences.xib @@ -19,14 +19,14 @@ - + - + - + @@ -49,7 +49,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -70,7 +70,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -88,7 +88,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -200,7 +200,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -229,16 +229,16 @@ - + - + - + @@ -263,12 +263,43 @@ - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +