Zonble: Add in-place phrase replacement system.
- Also write the settings to the user plist (OOBE).
This commit is contained in:
parent
70b22f9864
commit
707fb9ac99
|
@ -66,7 +66,8 @@ class AppDelegate: NSObject, NSApplicationDelegate,
|
|||
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
LanguageModelManager.loadDataModels()
|
||||
LanguageModelManager.loadUserPhrasesModel()
|
||||
LanguageModelManager.loadUserPhrases()
|
||||
LanguageModelManager.loadUserPhraseReplacement()
|
||||
|
||||
OOBE.setMissingDefaults()
|
||||
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// PhraseReplacementMap.cpp
|
||||
//
|
||||
// Copyright (c) 2011-2022 The OpenVanilla Project.
|
||||
//
|
||||
// Contributors:
|
||||
// Weizhong Yang (@zonble) @ OpenVanilla
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include "KeyValueBlobReader.h"
|
||||
#include "PhraseReplacementMap.h"
|
||||
|
||||
namespace vChewing {
|
||||
|
||||
using std::string;
|
||||
|
||||
PhraseReplacementMap::PhraseReplacementMap()
|
||||
: fd(-1)
|
||||
, data(0)
|
||||
, length(0)
|
||||
{
|
||||
}
|
||||
|
||||
PhraseReplacementMap::~PhraseReplacementMap()
|
||||
{
|
||||
if (data) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
bool PhraseReplacementMap::open(const char *path)
|
||||
{
|
||||
if (data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fd = ::open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
printf("open:: file not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
printf("open:: cannot open file");
|
||||
return false;
|
||||
}
|
||||
|
||||
length = (size_t)sb.st_size;
|
||||
|
||||
data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (!data) {
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyValueBlobReader reader(static_cast<char*>(data), length);
|
||||
KeyValueBlobReader::KeyValue keyValue;
|
||||
KeyValueBlobReader::State state;
|
||||
while ((state = reader.Next(&keyValue)) == KeyValueBlobReader::State::HAS_PAIR) {
|
||||
keyValueMap[keyValue.key] = keyValue.value;
|
||||
}
|
||||
|
||||
if (state == KeyValueBlobReader::State::ERROR) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PhraseReplacementMap::close()
|
||||
{
|
||||
if (data) {
|
||||
munmap(data, length);
|
||||
::close(fd);
|
||||
data = 0;
|
||||
}
|
||||
|
||||
keyValueMap.clear();
|
||||
}
|
||||
|
||||
const std::string PhraseReplacementMap::valueForKey(const std::string& key)
|
||||
{
|
||||
auto iter = keyValueMap.find(key);
|
||||
if (iter != keyValueMap.end()) {
|
||||
const std::string_view v = iter->second;
|
||||
return {v.data(), v.size()};
|
||||
}
|
||||
return string("");
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// PhraseReplacementMap.h
|
||||
//
|
||||
// Copyright (c) 2011-2022 The OpenVanilla Project.
|
||||
//
|
||||
// Contributors:
|
||||
// Weizhong Yang (@zonble) @ OpenVanilla
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#ifndef PHRASEREPLACEMENTMAP_H
|
||||
#define PHRASEREPLACEMENTMAP_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace vChewing {
|
||||
|
||||
class PhraseReplacementMap
|
||||
{
|
||||
public:
|
||||
PhraseReplacementMap();
|
||||
~PhraseReplacementMap();
|
||||
|
||||
bool open(const char *path);
|
||||
void close();
|
||||
const std::string valueForKey(const std::string& key);
|
||||
|
||||
protected:
|
||||
std::map<std::string_view, std::string_view> keyValueMap;
|
||||
int fd;
|
||||
void *data;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -50,6 +50,7 @@ vChewingLM::~vChewingLM()
|
|||
m_languageModel.close();
|
||||
m_userPhrases.close();
|
||||
m_excludedPhrases.close();
|
||||
m_phraseReplacement.close();
|
||||
}
|
||||
|
||||
void vChewingLM::loadLanguageModel(const char* languageModelDataPath)
|
||||
|
@ -73,6 +74,13 @@ void vChewingLM::loadUserPhrases(const char* userPhrasesDataPath,
|
|||
}
|
||||
}
|
||||
|
||||
void vChewingLM::loadPhraseReplacementMap(const char* phraseReplacementPath) {
|
||||
if (phraseReplacementPath) {
|
||||
m_phraseReplacement.close();
|
||||
m_phraseReplacement.open(phraseReplacementPath);
|
||||
}
|
||||
}
|
||||
|
||||
const vector<Bigram> vChewingLM::bigramsForKeys(const string& preceedingKey, const string& key)
|
||||
{
|
||||
return vector<Bigram>();
|
||||
|
@ -96,24 +104,45 @@ const vector<Unigram> vChewingLM::unigramsForKey(const string& key)
|
|||
|
||||
if (m_userPhrases.hasUnigramsForKey(key)) {
|
||||
vector<Unigram> rawUserUnigrams = m_userPhrases.unigramsForKey(key);
|
||||
|
||||
vector<Unigram> filterredUserUnigrams = m_userPhrases.unigramsForKey(key);
|
||||
|
||||
for (auto&& unigram : rawUserUnigrams) {
|
||||
if (excludedValues.find(unigram.keyValue.value) == excludedValues.end()) {
|
||||
userUnigrams.push_back(unigram);
|
||||
filterredUserUnigrams.push_back(unigram);
|
||||
}
|
||||
}
|
||||
|
||||
transform(userUnigrams.begin(), userUnigrams.end(),
|
||||
|
||||
transform(filterredUserUnigrams.begin(), filterredUserUnigrams.end(),
|
||||
inserter(userValues, userValues.end()),
|
||||
[](const Unigram &u) { return u.keyValue.value; });
|
||||
|
||||
if (m_phraseReplacementEnabled) {
|
||||
for (auto&& unigram : filterredUserUnigrams) {
|
||||
string value = unigram.keyValue.value;
|
||||
string replacement = m_phraseReplacement.valueForKey(value);
|
||||
if (replacement != "") {
|
||||
unigram.keyValue.value = replacement;
|
||||
}
|
||||
unigrams.push_back(unigram);
|
||||
}
|
||||
} else {
|
||||
unigrams = filterredUserUnigrams;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_languageModel.hasUnigramsForKey(key)) {
|
||||
vector<Unigram> globalUnigrams = m_languageModel.unigramsForKey(key);
|
||||
|
||||
|
||||
for (auto&& unigram : globalUnigrams) {
|
||||
if (excludedValues.find(unigram.keyValue.value) == excludedValues.end() &&
|
||||
userValues.find(unigram.keyValue.value) == userValues.end()) {
|
||||
string value = unigram.keyValue.value;
|
||||
if (excludedValues.find(value) == excludedValues.end() &&
|
||||
userValues.find(value) == userValues.end()) {
|
||||
if (m_phraseReplacementEnabled) {
|
||||
string replacement = m_phraseReplacement.valueForKey(value);
|
||||
if (replacement != "") {
|
||||
unigram.keyValue.value = replacement;
|
||||
}
|
||||
}
|
||||
unigrams.push_back(unigram);
|
||||
}
|
||||
}
|
||||
|
@ -132,3 +161,13 @@ bool vChewingLM::hasUnigramsForKey(const string& key)
|
|||
|
||||
return unigramsForKey(key).size() > 0;
|
||||
}
|
||||
|
||||
void vChewingLM::setPhraseReplacementEnabled(bool enabled)
|
||||
{
|
||||
m_phraseReplacementEnabled = enabled;
|
||||
}
|
||||
|
||||
bool vChewingLM::phraseReplacementEnabled()
|
||||
{
|
||||
return m_phraseReplacementEnabled;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <stdio.h>
|
||||
#include "FastLM.h"
|
||||
#include "UserPhrasesLM.h"
|
||||
#include "PhraseReplacementMap.h"
|
||||
|
||||
namespace vChewing {
|
||||
|
||||
|
@ -51,17 +52,23 @@ public:
|
|||
~vChewingLM();
|
||||
|
||||
void loadLanguageModel(const char* languageModelDataPath);
|
||||
void loadUserPhrases(const char* m_userPhrasesDataPath,
|
||||
const char* m_excludedPhrasesDataPath);
|
||||
void loadUserPhrases(const char* userPhrasesDataPath,
|
||||
const char* excludedPhrasesDataPath);
|
||||
void loadPhraseReplacementMap(const char* phraseReplacementPath);
|
||||
|
||||
const vector<Bigram> bigramsForKeys(const string& preceedingKey, const string& key);
|
||||
const vector<Unigram> unigramsForKey(const string& key);
|
||||
bool hasUnigramsForKey(const string& key);
|
||||
|
||||
void setPhraseReplacementEnabled(bool enabled);
|
||||
bool phraseReplacementEnabled();
|
||||
|
||||
protected:
|
||||
FastLM m_languageModel;
|
||||
UserPhrasesLM m_userPhrases;
|
||||
UserPhrasesLM m_excludedPhrases;
|
||||
PhraseReplacementMap m_phraseReplacement;
|
||||
bool m_phraseReplacementEnabled;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ private let kChooseCandidateUsingSpaceKey = "ChooseCandidateUsingSpaceKey"
|
|||
private let kSelectPhraseAfterCursorAsCandidate = "SelectPhraseAfterCursorAsCandidate"
|
||||
private let kUseHorizontalCandidateList = "UseHorizontalCandidateList"
|
||||
private let kChineseConversionEnabledKey = "ChineseConversionEnabled"
|
||||
private let kPhraseReplacementEnabledKey = "PhraseReplacementEnabled"
|
||||
|
||||
@objc public class OOBE : NSObject {
|
||||
|
||||
|
@ -76,6 +77,11 @@ private let kChineseConversionEnabledKey = "ChineseConversionEnabled"
|
|||
if UserDefaults.standard.object(forKey: kChineseConversionEnabledKey) == nil {
|
||||
UserDefaults.standard.set(Preferences.chineseConversionEnabled, forKey: kChineseConversionEnabledKey)
|
||||
}
|
||||
|
||||
// 預設停用自訂語彙置換
|
||||
if UserDefaults.standard.object(forKey: kPhraseReplacementEnabledKey) == nil {
|
||||
UserDefaults.standard.set(Preferences.phraseReplacementEnabled, forKey: kPhraseReplacementEnabledKey)
|
||||
}
|
||||
|
||||
// 預設沒事不要在那裡放屁
|
||||
if UserDefaults.standard.object(forKey: kShouldNotFartInLieuOfBeep) == nil {
|
||||
|
|
|
@ -140,6 +140,7 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
|
|||
|
||||
// create the lattice builder
|
||||
_languageModel = [LanguageModelManager languageModelBopomofo];
|
||||
_languageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled);
|
||||
_userOverrideModel = [LanguageModelManager userOverrideModel];
|
||||
|
||||
_builder = new BlockReadingBuilder(_languageModel);
|
||||
|
@ -158,22 +159,28 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
|
|||
|
||||
- (NSMenu *)menu
|
||||
{
|
||||
// Define the case which ALT / Option key is pressed.
|
||||
BOOL optionKeyPressed = [[NSEvent class] respondsToSelector:@selector(modifierFlags)] && ([NSEvent modifierFlags] & NSAlternateKeyMask);
|
||||
|
||||
// a menu instance (autoreleased) is requested every time the user click on the input menu
|
||||
NSMenu *menu = [[NSMenu alloc] initWithTitle:LocalizationNotNeeded(@"Input Method Menu")];
|
||||
|
||||
[menu addItemWithTitle:NSLocalizedString(@"vChewing Preferences", @"") action:@selector(showPreferences:) keyEquivalent:@""];
|
||||
|
||||
NSMenuItem *chineseConversionMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Chinese Conversion", @"") action:@selector(toggleChineseConverter:) keyEquivalent:@"K"];
|
||||
NSMenuItem *chineseConversionMenuItem = [menu addItemWithTitle:NSLocalizedString(@"Chinese Conversion", @"") action:@selector(toggleChineseConverter:) keyEquivalent:@"K"];
|
||||
chineseConversionMenuItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagControl;
|
||||
chineseConversionMenuItem.state = Preferences.chineseConversionEnabled ? NSControlStateValueOn : NSControlStateValueOff;
|
||||
[menu addItem:chineseConversionMenuItem];
|
||||
|
||||
NSMenuItem *halfWidthPunctuationMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Use Half-Width Punctuations", @"") action:@selector(toggleHalfWidthPunctuation:) keyEquivalent:@""];
|
||||
NSMenuItem *halfWidthPunctuationMenuItem = [menu addItemWithTitle:NSLocalizedString(@"Use Half-Width Punctuations", @"") action:@selector(toggleHalfWidthPunctuation:) keyEquivalent:@""];
|
||||
halfWidthPunctuationMenuItem.state = Preferences.halfWidthPunctuationEnabled ? NSControlStateValueOn : NSControlStateValueOff;
|
||||
[menu addItem:halfWidthPunctuationMenuItem];
|
||||
|
||||
if (optionKeyPressed) {
|
||||
NSMenuItem *phaseReplacementMenuItem = [menu addItemWithTitle:NSLocalizedString(@"Use Phrase Replacement", @"") action:@selector(togglePhraseReplacementEnabled:) keyEquivalent:@""];
|
||||
phaseReplacementMenuItem.state = Preferences.phraseReplacementEnabled ? NSControlStateValueOn : NSControlStateValueOff;
|
||||
}
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]]; // ------------------------------
|
||||
|
||||
|
||||
if (_inputMode == kSimpBopomofoModeIdentifier) {
|
||||
NSMenuItem *editExcludedPhrasesItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Excluded Phrases", @"") action:@selector(openExcludedPhrasesSimpBopomofo:) keyEquivalent:@""];
|
||||
[menu addItem:editExcludedPhrasesItem];
|
||||
|
@ -181,9 +188,12 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
|
|||
else {
|
||||
[menu addItemWithTitle:NSLocalizedString(@"Edit User Phrases", @"") action:@selector(openUserPhrases:) keyEquivalent:@""];
|
||||
[menu addItemWithTitle:NSLocalizedString(@"Edit Excluded Phrases", @"") action:@selector(openExcludedPhrasesvChewing:) keyEquivalent:@""];
|
||||
if (optionKeyPressed) {
|
||||
[menu addItemWithTitle:NSLocalizedString(@"Edit Phrase Replacement Table", @"") action:@selector(openPhraseReplacementvChewing:) keyEquivalent:@""];
|
||||
}
|
||||
}
|
||||
[menu addItemWithTitle:NSLocalizedString(@"Reload User Phrases", @"") action:@selector(reloadUserPhrases:) keyEquivalent:@""];
|
||||
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]]; // ------------------------------
|
||||
|
||||
[menu addItemWithTitle:NSLocalizedString(@"Check for Updates…", @"") action:@selector(checkForUpdate:) keyEquivalent:@""];
|
||||
|
@ -273,6 +283,7 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
|
|||
else {
|
||||
newInputMode = kBopomofoModeIdentifier;
|
||||
newLanguageModel = [LanguageModelManager languageModelBopomofo];
|
||||
newLanguageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled);
|
||||
}
|
||||
|
||||
// Only apply the changes if the value is changed
|
||||
|
@ -1486,6 +1497,27 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
|||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
- (void)toggleChineseConverter:(id)sender
|
||||
{
|
||||
BOOL chineseConversionEnabled = [Preferences toggleChineseConversionEnabled];
|
||||
[NotifierController notifyWithMessage:[NSString stringWithFormat:@"%@%@%@", NSLocalizedString(@"Chinese Conversion", @""), @"\n", chineseConversionEnabled ? NSLocalizedString(@"NotificationSwitchON", @"") : NSLocalizedString(@"NotificationSwitchOFF", @"")] stay:NO];
|
||||
}
|
||||
|
||||
- (void)toggleHalfWidthPunctuation:(id)sender
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||
[Preferences toogleHalfWidthPunctuationEnabled];
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
- (void)togglePhraseReplacementEnabled:(id)sender
|
||||
{
|
||||
BOOL enabled = [Preferences tooglePhraseReplacementEnabled];
|
||||
vChewingLM *lm = [LanguageModelManager languageModelBopomofo];
|
||||
lm->setPhraseReplacementEnabled(enabled);
|
||||
}
|
||||
|
||||
- (void)checkForUpdate:(id)sender
|
||||
{
|
||||
[(AppDelegate *)[[NSApplication sharedApplication] delegate] checkForUpdateForced:YES];
|
||||
|
@ -1526,9 +1558,15 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
|||
[self _openUserFile:[LanguageModelManager excludedPhrasesDataPathBopomofo]];
|
||||
}
|
||||
|
||||
- (void)openPhraseReplacementvChewing:(id)sender
|
||||
{
|
||||
[self _openUserFile:[LanguageModelManager phraseReplacementDataPathBopomofo]];
|
||||
}
|
||||
|
||||
- (void)reloadUserPhrases:(id)sender
|
||||
{
|
||||
[LanguageModelManager loadUserPhrasesModel];
|
||||
[LanguageModelManager loadUserPhrases];
|
||||
[LanguageModelManager loadUserPhraseReplacement];
|
||||
}
|
||||
|
||||
- (void)showAbout:(id)sender
|
||||
|
@ -1538,23 +1576,9 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
|||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
- (void)toggleChineseConverter:(id)sender
|
||||
{
|
||||
BOOL chineseConversionEnabled = [Preferences toggleChineseConversionEnabled];
|
||||
[NotifierController notifyWithMessage:[NSString stringWithFormat:@"%@%@%@", NSLocalizedString(@"Chinese Conversion", @""), @"\n", chineseConversionEnabled ? NSLocalizedString(@"NotificationSwitchON", @"") : NSLocalizedString(@"NotificationSwitchOFF", @"")] stay:NO];
|
||||
}
|
||||
|
||||
- (void)toggleHalfWidthPunctuation:(id)sender
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||
[Preferences toogleHalfWidthPunctuationEnabled];
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark - Voltaire
|
||||
|
||||
@implementation vChewingInputMethodController (VTCandidateController)
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface LanguageModelManager : NSObject
|
||||
|
||||
+ (void)loadDataModels;
|
||||
+ (void)loadUserPhrasesModel;
|
||||
+ (void)loadUserPhrases;
|
||||
+ (void)loadUserPhraseReplacement;
|
||||
+ (BOOL)checkIfUserLanguageModelFilesExist;
|
||||
+ (BOOL)writeUserPhrase:(NSString *)userPhrase;
|
||||
|
||||
|
@ -52,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (class, readonly, nonatomic) NSString *userPhrasesDataPathBopomofo;
|
||||
@property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathBopomofo;
|
||||
@property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathSimpBopomofo;
|
||||
@property (class, readonly, nonatomic) NSString *phraseReplacementDataPathBopomofo;
|
||||
@property (class, readonly, nonatomic) vChewing::vChewingLM *languageModelBopomofo;
|
||||
@property (class, readonly, nonatomic) vChewing::vChewingLM *languageModelSimpBopomofo;
|
||||
@property (class, readonly, nonatomic) vChewing::UserOverrideModel *userOverrideModel;
|
||||
|
|
|
@ -49,7 +49,7 @@ using namespace OpenVanilla;
|
|||
static const int kUserOverrideModelCapacity = 500;
|
||||
static const double kObservedOverrideHalflife = 5400.0; // 1.5 hr.
|
||||
|
||||
vChewingLM glanguageModelBopomofo;
|
||||
vChewingLM gLanguageModelBopomofo;
|
||||
vChewingLM gLanguageModelSimpBopomofo;
|
||||
UserOverrideModel gUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife);
|
||||
|
||||
|
@ -64,16 +64,21 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing
|
|||
|
||||
+ (void)loadDataModels
|
||||
{
|
||||
LTLoadLanguageModelFile(@"data", glanguageModelBopomofo);
|
||||
LTLoadLanguageModelFile(@"data", gLanguageModelBopomofo);
|
||||
LTLoadLanguageModelFile(@"data-plain-bpmf", gLanguageModelSimpBopomofo);
|
||||
}
|
||||
|
||||
+ (void)loadUserPhrasesModel
|
||||
+ (void)loadUserPhrases
|
||||
{
|
||||
glanguageModelBopomofo.loadUserPhrases([[self userPhrasesDataPathBopomofo] UTF8String], [[self excludedPhrasesDataPathBopomofo] UTF8String]);
|
||||
gLanguageModelBopomofo.loadUserPhrases([[self userPhrasesDataPathBopomofo] UTF8String], [[self excludedPhrasesDataPathBopomofo] UTF8String]);
|
||||
gLanguageModelSimpBopomofo.loadUserPhrases(NULL, [[self excludedPhrasesDataPathSimpBopomofo] UTF8String]);
|
||||
}
|
||||
|
||||
+ (void)loadUserPhraseReplacement
|
||||
{
|
||||
gLanguageModelBopomofo.loadPhraseReplacementMap([[self phraseReplacementDataPathBopomofo] UTF8String]);
|
||||
}
|
||||
|
||||
+ (BOOL)checkIfUserDataFolderExists
|
||||
{
|
||||
NSString *folderPath = [self dataFolderPath];
|
||||
|
@ -125,6 +130,9 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing
|
|||
if (![self checkIfFileExist:[self excludedPhrasesDataPathSimpBopomofo]]) {
|
||||
return NO;
|
||||
}
|
||||
if (![self checkIfFileExist:[self phraseReplacementDataPathBopomofo]]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -171,7 +179,7 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing
|
|||
[writeFile writeData:data];
|
||||
[writeFile closeFile];
|
||||
|
||||
[self loadUserPhrasesModel];
|
||||
[self loadUserPhrases];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -198,9 +206,14 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing
|
|||
return [[self dataFolderPath] stringByAppendingPathComponent:@"exclude-phrases-plain-bpmf.txt"];
|
||||
}
|
||||
|
||||
+ (NSString *)phraseReplacementDataPathBopomofo
|
||||
{
|
||||
return [[self dataFolderPath] stringByAppendingPathComponent:@"phrases-replacement.txt"];
|
||||
}
|
||||
|
||||
+ (vChewingLM *)languageModelBopomofo
|
||||
{
|
||||
return &glanguageModelBopomofo;
|
||||
return &gLanguageModelBopomofo;
|
||||
}
|
||||
|
||||
+ (vChewingLM *)languageModelSimpBopomofo
|
||||
|
|
|
@ -51,6 +51,7 @@ private let kCandidateTextFontName = "CandidateTextFontName"
|
|||
private let kCandidateKeyLabelFontName = "CandidateKeyLabelFontName"
|
||||
private let kCandidateKeys = "CandidateKeys"
|
||||
private let kChineseConversionEngineKey = "ChineseConversionEngine"
|
||||
private let kPhraseReplacementEnabledKey = "PhraseReplacementEnabled"
|
||||
|
||||
private let kDefaultCandidateListTextSize: CGFloat = 18
|
||||
private let kMinKeyLabelSize: CGFloat = 10
|
||||
|
@ -297,4 +298,12 @@ struct ComposingKeys {
|
|||
return ChineseConversionEngine(rawValue: chineseConversionEngine)?.name
|
||||
}
|
||||
|
||||
@UserDefault(key: kPhraseReplacementEnabledKey, defaultValue: false)
|
||||
@objc static var phraseReplacementEnabled: Bool
|
||||
|
||||
@objc static func tooglePhraseReplacementEnabled() -> Bool {
|
||||
phraseReplacementEnabled = !phraseReplacementEnabled
|
||||
UserDefaults.standard.set(phraseReplacementEnabled, forKey: kPhraseReplacementEnabledKey)
|
||||
return phraseReplacementEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,3 +27,5 @@
|
|||
"Use Half-Width Punctuations" = "Use Half-Width Punctuations";
|
||||
"You are now selecting \"%@\". You can add a phrase with two or more characters." = "You are now selecting \"%@\". You can add a phrase with two or more characters.";
|
||||
"You are now selecting \"%@\". Press enter to add a new phrase." = "You are now selecting \"%@\". Press enter to add a new phrase.";
|
||||
"Edit Phrase Replacement Table" = "Edit Phrase Replacement Table";
|
||||
"Use Phrase Replacement" = "Use Phrase Replacement";
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
#import <Foundation/Foundation.h> // @import Foundation;
|
||||
@interface LanguageModelManager : NSObject
|
||||
+ (void)loadDataModels;
|
||||
+ (void)loadUserPhrasesModel;
|
||||
+ (void)loadUserPhrases;
|
||||
+ (void)loadUserPhraseReplacement;
|
||||
@end
|
||||
|
|
|
@ -27,3 +27,5 @@
|
|||
"Use Half-Width Punctuations" = "啟用半角標點輸出";
|
||||
"You are now selecting \"%@\". You can add a phrase with two or more characters." = "您目前选择了「%@」。请选择至少两个字,才能将其加入自订语汇。";
|
||||
"You are now selecting \"%@\". Press enter to add a new phrase." = "您目前选择了「%@」。按下 Enter 就可以加入到自订语汇中。";
|
||||
"Edit Phrase Replacement Table" = "编辑语汇置换表";
|
||||
"Use Phrase Replacement" = "使用语汇置换";
|
||||
|
|
|
@ -27,3 +27,5 @@
|
|||
"Use Half-Width Punctuations" = "啟用半形標點輸出";
|
||||
"You are now selecting \"%@\". You can add a phrase with two or more characters." = "您目前選擇了「%@」。請選擇至少兩個字,才能將其加入自訂語彙。";
|
||||
"You are now selecting \"%@\". Press enter to add a new phrase." = "您目前選擇了「%@」。按下 Enter 就可以加入到自訂語彙中。";
|
||||
"Edit Phrase Replacement Table" = "編輯語彙置換表";
|
||||
"Use Phrase Replacement" = "使用語彙置換";
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
5B5F4F8E27928F9300922DC2 /* vChewingLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F4F8D27928F9300922DC2 /* vChewingLM.cpp */; };
|
||||
5B5F4F93279294A300922DC2 /* LanguageModelManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F4F92279294A300922DC2 /* LanguageModelManager.mm */; };
|
||||
5B5F4F972792A4EA00922DC2 /* UserPhrasesLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F4F962792A4EA00922DC2 /* UserPhrasesLM.cpp */; };
|
||||
5B6797B52794822C004AC7CE /* PhraseReplacementMap.h in Sources */ = {isa = PBXBuildFile; fileRef = 5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */; };
|
||||
5BC2D2872793B434002C0BEC /* CMakeLists.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BC2D2852793B434002C0BEC /* CMakeLists.txt */; };
|
||||
5BC2D2882793B434002C0BEC /* KeyValueBlobReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */; };
|
||||
5BC2D28B2793B8FB002C0BEC /* EmacsKeyHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28A2793B8FB002C0BEC /* EmacsKeyHelper.swift */; };
|
||||
|
@ -27,6 +28,7 @@
|
|||
5BD0D19A27943D390008F48E /* clsSFX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD0D19927943D390008F48E /* clsSFX.swift */; };
|
||||
5BD0D19F279454F60008F48E /* Beep.aif in Resources */ = {isa = PBXBuildFile; fileRef = 5BD0D19E279454F60008F48E /* Beep.aif */; };
|
||||
5BD0D1A4279463510008F48E /* clsOOBEDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD0D1A3279463510008F48E /* clsOOBEDefaults.swift */; };
|
||||
5BD13F482794F0A6000E429F /* PhraseReplacementMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B6797B42794822C004AC7CE /* PhraseReplacementMap.cpp */; };
|
||||
5BDF2CFE2791BE4400838ADB /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */; };
|
||||
5BDF2CFF2791BECC00838ADB /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */; };
|
||||
5BDF2D012791C03B00838ADB /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2D002791C03B00838ADB /* PreferencesWindowController.swift */; };
|
||||
|
@ -102,6 +104,8 @@
|
|||
5B5F4F92279294A300922DC2 /* LanguageModelManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LanguageModelManager.mm; sourceTree = "<group>"; };
|
||||
5B5F4F952792A4EA00922DC2 /* UserPhrasesLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserPhrasesLM.h; sourceTree = "<group>"; };
|
||||
5B5F4F962792A4EA00922DC2 /* UserPhrasesLM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UserPhrasesLM.cpp; sourceTree = "<group>"; };
|
||||
5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhraseReplacementMap.h; sourceTree = "<group>"; };
|
||||
5B6797B42794822C004AC7CE /* PhraseReplacementMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PhraseReplacementMap.cpp; sourceTree = "<group>"; };
|
||||
5B9781D32763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
5B9781D52763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
5B9781D72763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
|
@ -270,6 +274,8 @@
|
|||
5B42B63F27876FDC00BB9B9F /* UserOverrideModel.h */,
|
||||
5B5F4F962792A4EA00922DC2 /* UserPhrasesLM.cpp */,
|
||||
5B5F4F952792A4EA00922DC2 /* UserPhrasesLM.h */,
|
||||
5B6797B42794822C004AC7CE /* PhraseReplacementMap.cpp */,
|
||||
5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */,
|
||||
);
|
||||
path = LanguageModel;
|
||||
sourceTree = "<group>";
|
||||
|
@ -741,9 +747,11 @@
|
|||
5BD0D1A4279463510008F48E /* clsOOBEDefaults.swift in Sources */,
|
||||
D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */,
|
||||
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */,
|
||||
5B6797B52794822C004AC7CE /* PhraseReplacementMap.h in Sources */,
|
||||
6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */,
|
||||
5BDF2D012791C03B00838ADB /* PreferencesWindowController.swift in Sources */,
|
||||
5BC2D28D2793B98F002C0BEC /* PreferencesModule.swift in Sources */,
|
||||
5BD13F482794F0A6000E429F /* PhraseReplacementMap.cpp in Sources */,
|
||||
5BC3EE1C278FC48C00F5E44C /* VTCandidateController.swift in Sources */,
|
||||
5BDF2D032791C71200838ADB /* NonModalAlertWindowController.swift in Sources */,
|
||||
5BC3EE1D278FC48C00F5E44C /* HorizontalCandidateController.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue