Pre Merge pull request !33 from ShikiSuen/upd/1.5.9

This commit is contained in:
ShikiSuen 2022-05-18 10:07:51 +00:00 committed by Gitee
commit 01f5ca1d2a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
36 changed files with 1212 additions and 790 deletions

24
AUTHORS
View File

@ -1,14 +1,30 @@
$ Main contributors and volunteers of this repository (vChewing for macOS):
- Shiki Suen // Main developer of vChewing for macOS.
- Shiki Suen // Main developer of vChewing for macOS, Megrez language engine, and Tekkon syllable composer engine.
- Hiraku Wang // Technical reinforcement in Cocoa during the Object-Cpp dev period of this project.
- Isaac Xen // Technical reinforcement in Swift: SFX Module and StringView Ranges Extension.
$ Contributors and volunteeres of the upstream repo, having no responsibility in discussing anything in the current repo:
- Mengjuei Hsieh // McBopomofo for macOS 1.x main developer and architect.
- Zonble Yang // McBopomofo for macOS 2.x architect, especially state-based IME behavior management.
- Lukhnos D Liu // Developer of the Mandarin syllable input processor.
- Zonble Yang:
- McBopomofo for macOS 2.x architect, especially state-based IME behavior management.
- Voltaire candidate window MK2 (massively modified in vChewing by Shiki Suen).
- InputHandler.
- Notifier window and Tooltip UI.
- NSStringUtils and FSEventStreamHelper.
- App-style installer (only preserved for developer purposes).
- Mengjuei Hsieh
- McBopomofo for macOS 1.x main developer and architect.
- User Override Module (not enabled at this moment).
- Shiki Suen is trying to rewrite this module in Swift but it is not working yet.
Although there is no Lukhnos's codes left in the current repository, we still credit him for his previous work:
- Lukhnos Liu:
- Developer of Gramambular language engine (removed since vChewing 1.5.4).
- Shiki Suen's Megrez engine is basically a Swift-rewritten version of Gramambular.
- Developer of Mandarin syllable composer (removed since vChewing 1.5.7).
- Shiki Suen's Tekkon engine is made from scratch and has no relationship to Mandarin syllable composer.
$ Special thanks to:

View File

@ -24,21 +24,19 @@ VC_APP_ROOT = $(DSTROOT)/vChewing.app
format: batchfix clang-format lint
clang-format: clang-format-swift clang-format-cpp
clang-format-swift:
clang-format:
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format format --in-place --configuration ./.clang-format-swift.json --parallel
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
clang-format-cpp:
@git ls-files --exclude-standard | grep -E '\.(cpp|hpp|c|cc|cxx|hxx|ixx|h|m|mm|hh)$$' | xargs clang-format -i
lint:
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
batchfix:
@git ls-files --exclude-standard | grep -E '\.swift$$' | swiftlint --fix --autocorrect
advanced-lint:
@swiftformat --swiftversion 5.5 --indent 2 ./
.PHONY: permission-check install-debug install-release
permission-check:

@ -1 +1 @@
Subproject commit 383ad9af7dd6f9ffa58ad2560e186bf06ffea3ad
Subproject commit 1d2c6ac9571e3ef3552a1b610e26626d38af69cb

View File

@ -64,7 +64,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega
}
func applicationDidFinishLaunching(_: Notification) {
IME.initLangModels(userOnly: false)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
IME.initLangModels(userOnly: false)
}
fsStreamHelper.delegate = self
_ = fsStreamHelper.start()

View File

@ -57,10 +57,10 @@ import Cocoa
/// create a new user phrase.
/// - Choosing Candidate: The candidate window is open to let the user to choose
/// one among the candidates.
class InputState: NSObject {
class InputState {
/// Represents that the input controller is deactivated.
class Deactivated: InputState {
override var description: String {
var description: String {
"<InputState.Deactivated>"
}
}
@ -73,7 +73,7 @@ class InputState: NSObject {
""
}
override var description: String {
var description: String {
"<InputState.Empty>"
}
}
@ -86,7 +86,7 @@ class InputState: NSObject {
""
}
override var description: String {
var description: String {
"<InputState.EmptyIgnoringPreviousState>"
}
}
@ -102,7 +102,7 @@ class InputState: NSObject {
self.poppedText = poppedText
}
override var description: String {
var description: String {
"<InputState.Committing poppedText:\(poppedText)>"
}
}
@ -119,7 +119,7 @@ class InputState: NSObject {
self.cursorIndex = cursorIndex
}
override var description: String {
var description: String {
"<InputState.NotEmpty, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
}
}
@ -398,7 +398,7 @@ class InputState: NSObject {
super.init()
}
override var description: String {
var description: String {
"<InputState.AssociatedPhrases, candidates:\(candidates), useVerticalMode:\(useVerticalMode)>"
}
}
@ -421,20 +421,18 @@ class InputState: NSObject {
}
}
class SymbolNode: NSObject {
class SymbolNode {
var title: String
var children: [SymbolNode]?
init(_ title: String, _ children: [SymbolNode]? = nil) {
self.title = title
self.children = children
super.init()
}
init(_ title: String, symbols: String) {
self.title = title
children = Array(symbols).map { SymbolNode(String($0), nil) }
super.init()
}
static let catCommonSymbols = String(

View File

@ -34,7 +34,7 @@ public enum InputMode: String {
// MARK: - Delegate.
protocol KeyHandlerDelegate: NSObjectProtocol {
protocol KeyHandlerDelegate {
func ctlCandidate(for _: KeyHandler) -> Any
func keyHandler(
_: KeyHandler, didSelectCandidateAt index: Int,
@ -46,7 +46,7 @@ protocol KeyHandlerDelegate: NSObjectProtocol {
// MARK: - Kernel.
class KeyHandler: NSObject {
class KeyHandler {
let kEpsilon: Double = 0.000001
var _composer: Tekkon.Composer = .init()
var _inputMode: String = ""
@ -55,7 +55,7 @@ class KeyHandler: NSObject {
var _builder: Megrez.BlockReadingBuilder
var _walkedNodes: [Megrez.NodeAnchor] = []
weak var delegate: KeyHandlerDelegate?
var delegate: KeyHandlerDelegate?
var inputMode: InputMode {
get {
@ -71,9 +71,8 @@ class KeyHandler: NSObject {
set { setInputMode(newValue.rawValue) }
}
override init() {
public init() {
_builder = Megrez.BlockReadingBuilder(lm: _languageModel)
super.init()
ensureParser()
setInputMode(ctlInputMethod.currentInputMode)
}
@ -117,15 +116,11 @@ class KeyHandler: NSObject {
func walk() {
// Retrieve the most likely grid, i.e. a Maximum Likelihood Estimation
// of the best possible Mandarin characters given the input syllables,
// using the Viterbi algorithm implemented in the Megrez library
let walker = Megrez.Walker(grid: _builder.grid())
// the reverse walk traces the grid from the end
let walked = walker.reverseWalk(at: _builder.grid().width(), nodesLimit: 3, balanced: true)
// then we use ".reversed()" to reverse the nodes so that we get the forward-walked nodes
_walkedNodes.removeAll()
_walkedNodes.append(contentsOf: walked.reversed())
// using the Viterbi algorithm implemented in the Megrez library.
// The walk() traces the grid to the end, hence no need to use .reversed() here.
_walkedNodes = Megrez.Walker(
grid: _builder.grid()
).walk(at: _builder.grid().width(), nodesLimit: 3, balanced: true)
}
func popOverflowComposingTextAndWalk() -> String {
@ -171,17 +166,20 @@ class KeyHandler: NSObject {
// in the user override model.
var addToUserOverrideModel = true
if selectedNode.spanningLength != value.count {
IME.prtDebugIntel("UOM: SpanningLength != value.count, dismissing.")
addToUserOverrideModel = false
}
if addToUserOverrideModel {
if let theNode = selectedNode.node {
// SymbolLM Score -12
if theNode.scoreFor(candidate: value) <= -12 {
IME.prtDebugIntel("UOM: Score <= -12, dismissing.")
addToUserOverrideModel = false
}
}
}
if addToUserOverrideModel {
IME.prtDebugIntel("UOM: Start Observation.")
_userOverrideModel.observe(
walkedNodes: _walkedNodes, cursorIndex: cursorIndex, candidate: value,
timestamp: NSDate().timeIntervalSince1970
@ -237,11 +235,15 @@ class KeyHandler: NSObject {
)
if !overrideValue.isEmpty {
IME.prtDebugIntel(
"UOM: Suggestion retrieved, overriding the node score of the selected candidate.")
_builder.grid().overrideNodeScoreForSelectedCandidate(
location: getActualCandidateCursorIndex(),
value: overrideValue,
overridingScore: findHighestScore(nodes: getRawNodes(), epsilon: kEpsilon)
)
} else {
IME.prtDebugIntel("UOM: Blank suggestion retrieved, dismissing.")
}
}
@ -328,6 +330,8 @@ class KeyHandler: NSObject {
switch mgrPrefs.mandarinParser {
case MandarinParser.ofStandard.rawValue:
_composer.ensureParser(arrange: .ofDachen)
case MandarinParser.ofDachen26.rawValue:
_composer.ensureParser(arrange: .ofDachen26)
case MandarinParser.ofEten.rawValue:
_composer.ensureParser(arrange: .ofEten)
case MandarinParser.ofHsu.rawValue:
@ -340,11 +344,20 @@ class KeyHandler: NSObject {
_composer.ensureParser(arrange: .ofMiTAC)
case MandarinParser.ofFakeSeigyou.rawValue:
_composer.ensureParser(arrange: .ofFakeSeigyou)
case MandarinParser.ofHanyuPinyin.rawValue:
_composer.ensureParser(arrange: .ofHanyuPinyin)
case MandarinParser.ofSecondaryPinyin.rawValue:
_composer.ensureParser(arrange: .ofSecondaryPinyin)
case MandarinParser.ofYalePinyin.rawValue:
_composer.ensureParser(arrange: .ofYalePinyin)
case MandarinParser.ofHualuoPinyin.rawValue:
_composer.ensureParser(arrange: .ofHualuoPinyin)
case MandarinParser.ofUniversalPinyin.rawValue:
_composer.ensureParser(arrange: .ofUniversalPinyin)
default:
_composer.ensureParser(arrange: .ofDachen)
mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue
}
_composer.clear()
}
}

View File

@ -166,7 +166,7 @@ extension KeyHandler {
// However, Swift does not support "|=".
composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter))
if composeReading {
let reading = _composer.realComposition
let reading = _composer.getComposition()
// See whether we have a unigram for this...
if !ifLangModelHasUnigrams(forKey: reading) {

View File

@ -89,7 +89,7 @@ extension KeyHandler {
}
let head = rawHead
let reading = _composer.getComposition(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
let reading = _composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
let tail = rawEnd
let composedText = head + reading + tail
let cursorIndex = composedStringCursorIndex + reading.count
@ -256,16 +256,10 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback _: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard let currentState = state as? InputState.Inputting else { return false }
clear()
if let current = state as? InputState.Inputting {
stateCallback(InputState.Committing(poppedText: current.composingBuffer))
}
stateCallback(InputState.Committing(poppedText: currentState.composingBuffer))
stateCallback(InputState.Empty())
return true
}
@ -277,9 +271,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback _: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
var composingBuffer = currentReadings().joined(separator: "-")
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
@ -305,9 +297,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback _: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
var composed = ""
@ -346,9 +336,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
if _composer.hasToneMarker(withNothingElse: true) {
_composer.clear()
@ -381,9 +369,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
if _composer.isEmpty {
if getBuilderCursorIndex() != getBuilderLength() {
@ -417,9 +403,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
if !_composer.isEmpty {
IME.prtDebugIntel("9B6F908D")
errorCallback()
@ -435,9 +419,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
if !_composer.isEmpty {
IME.prtDebugIntel("ABC44080")
@ -465,9 +447,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) {
return false
}
guard state is InputState.Inputting else { return false }
if !_composer.isEmpty {
IME.prtDebugIntel("9B69908D")
@ -495,7 +475,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback _: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) { return false }
guard state is InputState.Inputting else { return false }
let escToClearInputBufferEnabled: Bool = mgrPrefs.escToCleanInputBuffer
@ -528,7 +508,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) { return false }
guard let currentState = state as? InputState.Inputting else { return false }
if !_composer.isEmpty {
IME.prtDebugIntel("B3BA5257")
@ -537,34 +517,32 @@ extension KeyHandler {
return true
}
if let currentState = state as? InputState.Inputting {
if input.isShiftHold {
// Shift + Right
if currentState.cursorIndex < (currentState.composingBuffer as NSString).length {
let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position(
for: Int(currentState.cursorIndex))
let marking: InputState.Marking! = InputState.Marking(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(nextPosition),
readings: currentReadings()
)
marking.tooltipForInputting = currentState.tooltip
stateCallback(marking)
} else {
IME.prtDebugIntel("BB7F6DB9")
errorCallback()
stateCallback(state)
}
if input.isShiftHold {
// Shift + Right
if currentState.cursorIndex < (currentState.composingBuffer as NSString).length {
let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position(
for: Int(currentState.cursorIndex))
let marking: InputState.Marking! = InputState.Marking(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(nextPosition),
readings: currentReadings()
)
marking.tooltipForInputting = currentState.tooltip
stateCallback(marking)
} else {
if getBuilderCursorIndex() < getBuilderLength() {
setBuilderCursorIndex(value: getBuilderCursorIndex() + 1)
stateCallback(buildInputtingState())
} else {
IME.prtDebugIntel("A96AAD58")
errorCallback()
stateCallback(state)
}
IME.prtDebugIntel("BB7F6DB9")
errorCallback()
stateCallback(state)
}
} else {
if getBuilderCursorIndex() < getBuilderLength() {
setBuilderCursorIndex(value: getBuilderCursorIndex() + 1)
stateCallback(buildInputtingState())
} else {
IME.prtDebugIntel("A96AAD58")
errorCallback()
stateCallback(state)
}
}
@ -579,7 +557,7 @@ extension KeyHandler {
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if !(state is InputState.Inputting) { return false }
guard let currentState = state as? InputState.Inputting else { return false }
if !_composer.isEmpty {
IME.prtDebugIntel("6ED95318")
@ -588,34 +566,32 @@ extension KeyHandler {
return true
}
if let currentState = state as? InputState.Inputting {
if input.isShiftHold {
// Shift + left
if currentState.cursorIndex > 0 {
let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position(
for: Int(currentState.cursorIndex))
let marking: InputState.Marking! = InputState.Marking(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(previousPosition),
readings: currentReadings()
)
marking.tooltipForInputting = currentState.tooltip
stateCallback(marking)
} else {
IME.prtDebugIntel("D326DEA3")
errorCallback()
stateCallback(state)
}
if input.isShiftHold {
// Shift + left
if currentState.cursorIndex > 0 {
let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position(
for: Int(currentState.cursorIndex))
let marking: InputState.Marking! = InputState.Marking(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(previousPosition),
readings: currentReadings()
)
marking.tooltipForInputting = currentState.tooltip
stateCallback(marking)
} else {
if getBuilderCursorIndex() > 0 {
setBuilderCursorIndex(value: getBuilderCursorIndex() - 1)
stateCallback(buildInputtingState())
} else {
IME.prtDebugIntel("7045E6F3")
errorCallback()
stateCallback(state)
}
IME.prtDebugIntel("D326DEA3")
errorCallback()
stateCallback(state)
}
} else {
if getBuilderCursorIndex() > 0 {
setBuilderCursorIndex(value: getBuilderCursorIndex() - 1)
stateCallback(buildInputtingState())
} else {
IME.prtDebugIntel("7045E6F3")
errorCallback()
stateCallback(state)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@ extension String {
}
}
class vChewingKanjiConverter: NSObject {
class vChewingKanjiConverter {
class func cnvTradToKangXi(_ strObj: String) -> String {
var strObj = strObj
strObj.selfReplace("", "")

View File

@ -30,7 +30,7 @@ public protocol FSEventStreamHelperDelegate: AnyObject {
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event])
}
public class FSEventStreamHelper: NSObject {
public class FSEventStreamHelper {
public struct Event {
var path: String
var flags: FSEventStreamEventFlags
@ -41,7 +41,7 @@ public class FSEventStreamHelper: NSObject {
public let dispatchQueue: DispatchQueue
public weak var delegate: FSEventStreamHelperDelegate?
@objc public init(path: String, queue: DispatchQueue) {
public init(path: String, queue: DispatchQueue) {
self.path = path
dispatchQueue = queue
}

View File

@ -28,7 +28,7 @@ import Cocoa
// The namespace of this input method.
public enum vChewing {}
public class IME: NSObject {
public enum IME {
static let arrSupportedLocales = ["en", "zh-Hant", "zh-Hans", "ja"]
static let dlgOpenPath = NSOpenPanel()
@ -364,7 +364,7 @@ extension String: LocalizedError {
}
}
// MARK: - Ensuring trailing slash of a string:
// MARK: - Ensuring trailing slash of a string
extension String {
mutating func ensureTrailingSlash() {
@ -373,3 +373,16 @@ extension String {
}
}
}
// MARK: - CharCode printability check
// Ref: https://forums.swift.org/t/57085/5
extension UniChar {
public func isPrintable() -> Bool {
guard Unicode.Scalar(UInt32(self)) != nil else {
struct NotAWholeScalar: Error {}
return false
}
return true
}
}

View File

@ -148,7 +148,7 @@ class ctlInputMethod: IMKInputController {
return Int(events.rawValue)
}
override func handle(_ event: NSEvent!, client: Any!) -> Bool {
@objc(handleEvent:client:) override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
// flags使 KeyHandler
// flags
// event.type == .flagsChanged return false
@ -161,13 +161,18 @@ class ctlInputMethod: IMKInputController {
ctlInputMethod.areWeDeleting = event.modifierFlags.contains([.shift, .command])
var textFrame = NSRect.zero
let attributes: [AnyHashable: Any]? = (client as? IMKTextInput)?.attributes(
guard let client = sender as? IMKTextInput else {
return false
}
let attributes: [AnyHashable: Any]? = client.attributes(
forCharacterIndex: 0, lineHeightRectangle: &textFrame
)
let useVerticalMode =
(attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false
if (client as? IMKTextInput)?.bundleIdentifier()
if client.bundleIdentifier()
== "org.atelierInmu.vChewing.vChewingPhraseEditor"
{
IME.areWeUsingOurOwnPhraseEditor = true
@ -177,6 +182,12 @@ class ctlInputMethod: IMKInputController {
let input = InputHandler(event: event, isVerticalMode: useVerticalMode)
//
// KeyHandler
if !input.charCode.isPrintable() {
return false
}
let result = keyHandler.handle(input: input, state: state) { newState in
self.handle(state: newState, client: client)
} errorCallback: {

View File

@ -166,7 +166,7 @@ struct ComposingBufferSize {
// MARK: -
@objc enum MandarinParser: Int {
enum MandarinParser: Int {
case ofStandard = 0
case ofEten = 1
case ofHsu = 2
@ -174,7 +174,12 @@ struct ComposingBufferSize {
case ofIBM = 4
case ofMiTAC = 5
case ofFakeSeigyou = 6
case ofDachen26 = 7
case ofHanyuPinyin = 10
case ofSecondaryPinyin = 11
case ofYalePinyin = 12
case ofHualuoPinyin = 13
case ofUniversalPinyin = 14
var name: String {
switch self {
@ -192,15 +197,25 @@ struct ComposingBufferSize {
return "MiTAC"
case .ofFakeSeigyou:
return "FakeSeigyou"
case .ofDachen26:
return "Dachen26"
case .ofHanyuPinyin:
return "HanyuPinyin"
case .ofSecondaryPinyin:
return "SecondaryPinyin"
case .ofYalePinyin:
return "YalePinyin"
case .ofHualuoPinyin:
return "HualuoPinyin"
case .ofUniversalPinyin:
return "UniversalPinyin"
}
}
}
// MARK: -
public class mgrPrefs: NSObject {
public enum mgrPrefs {
static var allKeys: [String] {
[
UserDef.kIsDebugModeEnabled,
@ -278,9 +293,11 @@ public class mgrPrefs: NSObject {
UserDefaults.standard.setDefault(mgrPrefs.phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled)
UserDefaults.standard.setDefault(mgrPrefs.shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep)
UserDefaults.standard.setDefault(
mgrPrefs.showHanyuPinyinInCompositionBuffer, forKey: UserDef.kShowHanyuPinyinInCompositionBuffer)
mgrPrefs.showHanyuPinyinInCompositionBuffer, forKey: UserDef.kShowHanyuPinyinInCompositionBuffer
)
UserDefaults.standard.setDefault(
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin)
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin
)
UserDefaults.standard.synchronize()
}
@ -310,7 +327,7 @@ public class mgrPrefs: NSObject {
static var appleLanguages: [String]
@UserDefault(key: UserDef.kMandarinParser, defaultValue: 0)
@objc static var mandarinParser: Int
static var mandarinParser: Int
static var mandarinParserName: String {
(MandarinParser(rawValue: mandarinParser) ?? MandarinParser.ofStandard).name

View File

@ -270,6 +270,7 @@ extension vChewing {
filter filteredPairs: Set<Megrez.KeyValuePair>
) -> [Megrez.Unigram] {
var results: [Megrez.Unigram] = []
var insertedPairs: Set<Megrez.KeyValuePair> = []
for unigram in unigrams {
var pair: Megrez.KeyValuePair = unigram.keyValue
@ -284,12 +285,13 @@ extension vChewing {
pair.value = replacement
}
}
results.append(Megrez.Unigram(keyValue: pair, score: unigram.score))
}
// Swift Swift-Collections OrderedSet NSOrderedSet
let resultsDeduplicated = Array(NSOrderedSet(array: results).array as! [Megrez.Unigram])
return resultsDeduplicated
if !insertedPairs.contains(pair) {
results.append(Megrez.Unigram(keyValue: pair, score: unigram.score))
insertedPairs.insert(pair)
}
}
return results
}
}
}

View File

@ -1,220 +0,0 @@
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
/*
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:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. 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 above.
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 "UserOverrideModel.h"
#include <cassert>
#include <cmath>
#include <sstream>
namespace vChewing
{
// About 20 generations.
static const double DecayThreshold = 1.0 / 1048576.0;
static double Score(size_t eventCount, size_t totalCount, double eventTimestamp, double timestamp, double lambda);
static bool IsEndingPunctuation(const std::string &value);
static std::string WalkedNodesToKey(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex);
UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant) : m_capacity(capacity)
{
assert(m_capacity > 0);
m_decayExponent = log(0.5) / decayConstant;
}
void UserOverrideModel::observe(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex,
const std::string &candidate, double timestamp)
{
std::string key = WalkedNodesToKey(walkedNodes, cursorIndex);
auto mapIter = m_lruMap.find(key);
if (mapIter == m_lruMap.end())
{
auto keyValuePair = KeyObservationPair(key, Observation());
Observation &observation = keyValuePair.second;
observation.update(candidate, timestamp);
m_lruList.push_front(keyValuePair);
auto listIter = m_lruList.begin();
auto lruKeyValue = std::pair<std::string, std::list<KeyObservationPair>::iterator>(key, listIter);
m_lruMap.insert(lruKeyValue);
if (m_lruList.size() > m_capacity)
{
auto lastKeyValuePair = m_lruList.end();
--lastKeyValuePair;
m_lruMap.erase(lastKeyValuePair->first);
m_lruList.pop_back();
}
}
else
{
auto listIter = mapIter->second;
m_lruList.splice(m_lruList.begin(), m_lruList, listIter);
auto &keyValuePair = *listIter;
Observation &observation = keyValuePair.second;
observation.update(candidate, timestamp);
}
}
std::string UserOverrideModel::suggest(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex,
double timestamp)
{
std::string key = WalkedNodesToKey(walkedNodes, cursorIndex);
auto mapIter = m_lruMap.find(key);
if (mapIter == m_lruMap.end())
{
return std::string();
}
auto listIter = mapIter->second;
auto &keyValuePair = *listIter;
const Observation &observation = keyValuePair.second;
std::string candidate;
double score = 0.0;
for (auto i = observation.overrides.begin(); i != observation.overrides.end(); ++i)
{
const Override &o = i->second;
double overrideScore = Score(o.count, observation.count, o.timestamp, timestamp, m_decayExponent);
if (overrideScore == 0.0)
{
continue;
}
if (overrideScore > score)
{
candidate = i->first;
score = overrideScore;
}
}
return candidate;
}
void UserOverrideModel::Observation::update(const std::string &candidate, double timestamp)
{
count++;
auto &o = overrides[candidate];
o.timestamp = timestamp;
o.count++;
}
static double Score(size_t eventCount, size_t totalCount, double eventTimestamp, double timestamp, double lambda)
{
double decay = exp((timestamp - eventTimestamp) * lambda);
if (decay < DecayThreshold)
{
return 0.0;
}
double prob = (double)eventCount / (double)totalCount;
return prob * decay;
}
static bool IsEndingPunctuation(const std::string &value)
{
return value == "" || value == "" || value == "" || value == "" || value == "" || value == "" ||
value == "" || value == "";
}
static std::string WalkedNodesToKey(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex)
{
std::stringstream s;
std::vector<Gramambular::NodeAnchor> n;
size_t ll = 0;
for (std::vector<Gramambular::NodeAnchor>::const_iterator i = walkedNodes.begin(); i != walkedNodes.end(); ++i)
{
const auto &nn = *i;
n.push_back(nn);
ll += nn.spanningLength;
if (ll >= cursorIndex)
{
break;
}
}
std::vector<Gramambular::NodeAnchor>::const_reverse_iterator r = n.rbegin();
if (r == n.rend())
{
return "";
}
std::string current = (*r).node->currentKeyValue().key;
++r;
s.clear();
s.str(std::string());
if (r != n.rend())
{
std::string value = (*r).node->currentKeyValue().value;
if (IsEndingPunctuation(value))
{
s << "()";
r = n.rend();
}
else
{
s << "(" << (*r).node->currentKeyValue().key << "," << value << ")";
++r;
}
}
else
{
s << "()";
}
std::string prev = s.str();
s.clear();
s.str(std::string());
if (r != n.rend())
{
std::string value = (*r).node->currentKeyValue().value;
if (IsEndingPunctuation(value))
{
s << "()";
r = n.rend();
}
else
{
s << "(" << (*r).node->currentKeyValue().key << "," << value << ")";
++r;
}
}
else
{
s << "()";
}
std::string anterior = s.str();
s.clear();
s.str(std::string());
s << "(" << anterior << "," << prev << "," << current << ")";
return s.str();
}
} // namespace vChewing

View File

@ -1,82 +0,0 @@
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
/*
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:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. 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 above.
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 USEROVERRIDEMODEL_H
#define USEROVERRIDEMODEL_H
#include <list>
#include <map>
#include "Gramambular.h"
namespace vChewing
{
using namespace Gramambular;
class UserOverrideModel
{
public:
UserOverrideModel(size_t capacity, double decayConstant);
void observe(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex,
const std::string &candidate, double timestamp);
std::string suggest(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex, double timestamp);
private:
struct Override
{
size_t count;
double timestamp;
Override() : count(0), timestamp(0.0)
{
}
};
struct Observation
{
size_t count;
std::map<std::string, Override> overrides;
Observation() : count(0)
{
}
void update(const std::string &candidate, double timestamp);
};
typedef std::pair<std::string, Observation> KeyObservationPair;
size_t m_capacity;
double m_decayExponent;
std::list<KeyObservationPair> m_lruList;
std::map<std::string, std::list<KeyObservationPair>::iterator> m_lruMap;
};
}; // namespace vChewing
#endif

View File

@ -95,7 +95,7 @@ extension vChewing {
if let arrRangeRecords: [Range<String.Index>] = rangeMap[key] {
for netaRange in arrRangeRecords {
let neta = strData[netaRange].split(separator: " ")
let theValue: String = String(neta[1])
let theValue: String = .init(neta[1])
pairs.append(theValue)
}
}

View File

@ -1,6 +1,5 @@
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
// Refactored from the ObjCpp-version of this class by:
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
// Refactored from the ObjCpp-version of this class by Mengjuei Hsieh (MIT License).
/*
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
@ -68,7 +67,7 @@ extension vChewing {
var mutCapacity: Int
var mutDecayExponent: Double
var mutLRUList = [KeyObservationPair]()
var mutLRUList: [KeyObservationPair] = []
var mutLRUMap: [String: KeyObservationPair] = [:]
let kDecayThreshold: Double = 1.0 / 1_048_576.0
@ -86,27 +85,27 @@ extension vChewing {
candidate: String,
timestamp: Double
) {
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
guard !key.isEmpty
else {
return
}
let key = convertKeyFrom(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
guard mutLRUMap[key] != nil else {
var observation: Observation = .init()
observation.update(candidate: candidate, timestamp: timestamp)
mutLRUMap[key] = KeyObservationPair(key: key, observation: observation)
mutLRUList.insert(KeyObservationPair(key: key, observation: observation), at: 0)
let koPair = KeyObservationPair(key: key, observation: observation)
mutLRUMap[key] = koPair
mutLRUList.insert(koPair, at: 0)
if mutLRUList.count > mutCapacity {
mutLRUMap[mutLRUList.reversed()[0].key] = nil
mutLRUMap[mutLRUList[mutLRUList.endIndex].key] = nil
mutLRUList.removeLast()
}
IME.prtDebugIntel("UOM: Observation finished with new observation: \(key)")
return
}
mutLRUList.insert(contentsOf: mutLRUMap.values, at: 0)
if mutLRUMap[key] != nil {
mutLRUMap[key]?.observation.update(candidate: candidate, timestamp: timestamp)
if var theNeta = mutLRUMap[key] {
theNeta.observation.update(candidate: candidate, timestamp: timestamp)
mutLRUList.insert(theNeta, at: 0)
mutLRUMap[key] = theNeta
IME.prtDebugIntel("UOM: Observation finished with existing observation: \(key)")
}
}
@ -115,25 +114,22 @@ extension vChewing {
cursorIndex: Int,
timestamp: Double
) -> String {
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
guard let keyValuePair = mutLRUMap[key],
!key.isEmpty
else {
let key = convertKeyFrom(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
guard let koPair = mutLRUMap[key] else {
IME.prtDebugIntel("UOM: mutLRUMap[key] is nil, throwing blank suggestion for key: \(key).")
return ""
}
IME.prtDebugIntel("Suggest - A: \(key)")
IME.prtDebugIntel("Suggest - B: \(keyValuePair.key)")
let observation = keyValuePair.observation
let observation = koPair.observation
var candidate = ""
var score = 0.0
for overrideNeta in Array(observation.overrides) {
let overrideScore = getScore(
eventCount: overrideNeta.value.count,
let override: Override = overrideNeta.value
let overrideScore: Double = getScore(
eventCount: override.count,
totalCount: observation.count,
eventTimestamp: overrideNeta.value.timestamp,
eventTimestamp: override.timestamp,
timestamp: timestamp,
lambda: mutDecayExponent
)
@ -147,13 +143,12 @@ extension vChewing {
score = overrideScore
}
}
if candidate.isEmpty {
IME.prtDebugIntel("UOM: No usable suggestions in the result for key: \(key).")
}
return candidate
}
func isEndingPunctuation(value: String) -> Bool {
["", "", "", "", "", "", "", ""].contains(value)
}
public func getScore(
eventCount: Int,
totalCount: Int,
@ -170,58 +165,51 @@ extension vChewing {
return prob * decay
}
func getWalkedNodesToKey(
func convertKeyFrom(
walkedNodes: [Megrez.NodeAnchor], cursorIndex: Int
) -> String {
var strOutput = ""
var arrNodes: [Megrez.NodeAnchor] = []
let arrEndingPunctuation = ["", "", "", "", "", "", "", ""]
var arrNodesReversed: [Megrez.NodeAnchor] = []
var intLength = 0
for nodeNeta in walkedNodes {
arrNodes.append(nodeNeta)
intLength += nodeNeta.spanningLength
for theNodeAnchor in walkedNodes {
// .reverse()
arrNodesReversed = [theNodeAnchor] + arrNodesReversed
intLength += theNodeAnchor.spanningLength
if intLength >= cursorIndex {
break
}
}
// .reversed 使 Swift
//
var arrNodesReversed: [Megrez.NodeAnchor] = []
arrNodesReversed.append(contentsOf: arrNodes.reversed())
if arrNodesReversed.isEmpty { return "" }
if arrNodesReversed.isEmpty {
var strCurrent = "()"
var strPrevious = "()"
var strAnterior = "()"
guard let kvCurrent = arrNodesReversed[0].node?.currentKeyValue(),
!arrEndingPunctuation.contains(kvCurrent.value)
else {
return ""
}
var strCurrent = "()"
var strPrev = "()"
var strAnterior = "()"
//
strCurrent = kvCurrent.key
for (theIndex, theAnchor) in arrNodesReversed.enumerated() {
if strCurrent != "()", let nodeCurrent = theAnchor.node {
let keyCurrent = nodeCurrent.currentKeyValue().key
let valCurrent = nodeCurrent.currentKeyValue().value
strCurrent = "(\(keyCurrent), \(valCurrent))"
if let nodePrev = arrNodesReversed[theIndex + 1].node {
let keyPrev = nodePrev.currentKeyValue().key
let valPrev = nodePrev.currentKeyValue().value
strPrev = "(\(keyPrev), \(valPrev))"
}
if let nodeAnterior = arrNodesReversed[theIndex + 2].node {
let keyAnterior = nodeAnterior.currentKeyValue().key
let valAnterior = nodeAnterior.currentKeyValue().value
strAnterior = "(\(keyAnterior), \(valAnterior))"
}
break //
}
if arrNodesReversed.count >= 2,
let kvPrevious = arrNodesReversed[1].node?.currentKeyValue(),
!arrEndingPunctuation.contains(kvPrevious.value)
{
strPrevious = "(\(kvPrevious.key),\(kvPrevious.value))"
}
strOutput = "(\(strAnterior),\(strPrev),\(strCurrent))"
if strOutput == "((),(),())" {
strOutput = ""
if arrNodesReversed.count >= 3,
let kvAnterior = arrNodesReversed[2].node?.currentKeyValue(),
!arrEndingPunctuation.contains(kvAnterior.value)
{
strAnterior = "(\(kvAnterior.key),\(kvAnterior.value))"
}
return strOutput
return "(\(strAnterior),\(strPrevious),\(strCurrent))"
}
}
}

View File

@ -36,7 +36,7 @@ private var gLangModelCHT = vChewing.LMInstantiator()
private var gUserOverrideModelCHS = vChewing.LMUserOverride()
private var gUserOverrideModelCHT = vChewing.LMUserOverride()
class mgrLangModel: NSObject {
enum mgrLangModel {
/// fileprivate
public static var lmCHS: vChewing.LMInstantiator { gLangModelCHS }
public static var lmCHT: vChewing.LMInstantiator { gLangModelCHT }

View File

@ -31,6 +31,25 @@ extension Megrez {
mutGrid = grid
}
public func walk(
at location: Int,
score accumulatedScore: Double = 0.0,
nodesLimit: Int = 0,
balanced: Bool = false
) -> [NodeAnchor] {
var arrReturn: [NodeAnchor] = []
let arrReversedSource = reverseWalk(
at: location, score: accumulatedScore,
nodesLimit: nodesLimit, balanced: balanced
).reversed()
for neta in arrReversedSource {
arrReturn.append(neta)
}
return arrReturn
}
public func reverseWalk(
at location: Int,
score accumulatedScore: Double = 0.0,

View File

@ -128,15 +128,17 @@ extension Megrez {
public func fixNodeSelectedCandidate(location: Int, value: String) -> NodeAnchor {
var node = NodeAnchor()
for (index, nodeAnchor) in nodesCrossingOrEndingAt(location: location).enumerated() {
for nodeAnchor in nodesCrossingOrEndingAt(location: location) {
guard let theNode = nodeAnchor.node else {
continue
}
let candidates = theNode.candidates()
// Reset the candidate-fixed state of every node at the location.
let candidates = nodeAnchor.node?.candidates() ?? []
nodesCrossingOrEndingAt(location: location)[index].node?.resetCandidate()
theNode.resetCandidate()
for (i, candidate) in candidates.enumerated() {
if candidate.value == value {
nodesCrossingOrEndingAt(location: location)[index].node?.selectCandidateAt(index: i)
node = nodesCrossingOrEndingAt(location: location)[index]
theNode.selectCandidateAt(index: i)
node = nodeAnchor
break
}
}
@ -145,19 +147,17 @@ extension Megrez {
}
public func overrideNodeScoreForSelectedCandidate(location: Int, value: String, overridingScore: Double) {
for (index, nodeAnchor) in nodesCrossingOrEndingAt(location: location).enumerated() {
if let theNode = nodeAnchor.node {
let candidates = theNode.candidates()
// Reset the candidate-fixed state of every node at the location.
nodesCrossingOrEndingAt(location: location)[index].node?.resetCandidate()
for (i, candidate) in candidates.enumerated() {
if candidate.value == value {
nodesCrossingOrEndingAt(location: location)[index].node?.selectFloatingCandidateAt(
index: i, score: overridingScore
)
break
}
for nodeAnchor in nodesCrossingOrEndingAt(location: location) {
guard let theNode = nodeAnchor.node else {
continue
}
let candidates = theNode.candidates()
// Reset the candidate-fixed state of every node at the location.
theNode.resetCandidate()
for (i, candidate) in candidates.enumerated() {
if candidate.value == value {
theNode.selectFloatingCandidateAt(index: i, score: overridingScore)
break
}
}
}

View File

@ -85,6 +85,7 @@
"Apple Chewing - Dachen" = "Apple Chewing - Dachen";
"Apple Chewing - Eten Traditional" = "Apple Chewing - Eten Traditional";
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters";
"Auto-convert traditional Chinese glyphs to KangXi characters" = "Auto-convert traditional Chinese glyphs to KangXi characters";
"Automatically reload user data files if changes detected" = "Automatically reload user data files if changes detected";
@ -104,6 +105,7 @@
"Choose your preferred layout of the candidate window." = "Choose your preferred layout of the candidate window.";
"Cursor Selection:" = "Cursor Selection:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "Dachen (Microsoft Standard / Wang / 01, etc.)";
"Dachen 26 (libChewing)" = "Dachen 26 (libChewing)";
"Debug Mode" = "Debug Mode";
"Dictionary" = "Dictionary";
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
@ -122,7 +124,9 @@
"Hanyu Pinyin with Numeral Intonation" = "Hanyu Pinyin with Numeral Intonation";
"Horizontal" = "Horizontal";
"Hsu" = "Hsu";
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
"IBM" = "IBM";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
"Japanese" = "Japanese";
"Keyboard" = "Keyboard";
"Misc Settings:" = "Misc Settings:";
@ -132,6 +136,7 @@
"Output Settings:" = "Output Settings:";
"Phonetic Parser:" = "Phonetic Parser:";
"Push the cursor in front of the phrase after selection" = "Push the cursor in front of the phrase after selection";
"Secondary Pinyin with Numeral Intonation" = "Secondary Pinyin with Numeral Intonation";
"Selection Keys:" = "Selection Keys:";
"Show Hanyu-Pinyin in the inline composition buffer" = "Show Hanyu-Pinyin in the inline composition buffer";
"Show page buttons in candidate window" = "Show page buttons in candidate window";
@ -140,10 +145,10 @@
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages";
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
"Traditional Chinese" = "Traditional Chinese";
"Typing Style:" = "Typing Style:";
"UI Language:" = "UI Language:";
"Universal Pinyin with Numeral Intonation" = "Universal Pinyin with Numeral Intonation";
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
"Vertical" = "Vertical";
"Yale Pinyin with Numeral Intonation" = "Yale Pinyin with Numeral Intonation";

View File

@ -85,6 +85,7 @@
"Apple Chewing - Dachen" = "Apple Chewing - Dachen";
"Apple Chewing - Eten Traditional" = "Apple Chewing - Eten Traditional";
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters";
"Auto-convert traditional Chinese glyphs to KangXi characters" = "Auto-convert traditional Chinese glyphs to KangXi characters";
"Automatically reload user data files if changes detected" = "Automatically reload user data files if changes detected";
@ -104,6 +105,7 @@
"Choose your preferred layout of the candidate window." = "Choose your preferred layout of the candidate window.";
"Cursor Selection:" = "Cursor Selection:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "Dachen (Microsoft Standard / Wang / 01, etc.)";
"Dachen 26 (libChewing)" = "Dachen 26 (libChewing)";
"Debug Mode" = "Debug Mode";
"Dictionary" = "Dictionary";
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
@ -122,7 +124,9 @@
"Hanyu Pinyin with Numeral Intonation" = "Hanyu Pinyin with Numeral Intonation";
"Horizontal" = "Horizontal";
"Hsu" = "Hsu";
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
"IBM" = "IBM";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
"Japanese" = "Japanese";
"Keyboard" = "Keyboard";
"Misc Settings:" = "Misc Settings:";
@ -132,6 +136,7 @@
"Output Settings:" = "Output Settings:";
"Phonetic Parser:" = "Phonetic Parser:";
"Push the cursor in front of the phrase after selection" = "Push the cursor in front of the phrase after selection";
"Secondary Pinyin with Numeral Intonation" = "Secondary Pinyin with Numeral Intonation";
"Selection Keys:" = "Selection Keys:";
"Show Hanyu-Pinyin in the inline composition buffer" = "Show Hanyu-Pinyin in the inline composition buffer";
"Show page buttons in candidate window" = "Show page buttons in candidate window";
@ -140,10 +145,10 @@
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages";
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
"Traditional Chinese" = "Traditional Chinese";
"Typing Style:" = "Typing Style:";
"UI Language:" = "UI Language:";
"Universal Pinyin with Numeral Intonation" = "Universal Pinyin with Numeral Intonation";
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
"Vertical" = "Vertical";
"Yale Pinyin with Numeral Intonation" = "Yale Pinyin with Numeral Intonation";

View File

@ -85,6 +85,7 @@
"Apple Chewing - Dachen" = "Apple 大千注音キーボード";
"Apple Chewing - Eten Traditional" = "Apple 倚天傳統キーボード";
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の配列を大千と設定すべきである。";
"at anyplace else (like Windows Yahoo KeyKey)" = "単語の中・後で // Windows Yahoo KeyKey のやり方";
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "入力した繁体字を日文 JIS 新字体と自動変換";
"Auto-convert traditional Chinese glyphs to KangXi characters" = "入力した繁体字を康熙字体と自動変換";
"Automatically reload user data files if changes detected" = "ユーザー辞書データの変更を自動検出し、自動的に再読込";
@ -104,6 +105,7 @@
"Choose your preferred layout of the candidate window." = "入力候補陳列の仕様をご指定ください。";
"Cursor Selection:" = "カーソル候補呼出:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (Microsoft 標準・王安・零壹など)";
"Dachen 26 (libChewing)" = "酷音大千 26 キー配列";
"Debug Mode" = "欠陥辿着モード";
"Dictionary" = "辞書設定";
"Emulating select-candidate-per-character mode" = "漢字1つづつ全候補選択入力モード";
@ -122,7 +124,9 @@
"Hanyu Pinyin with Numeral Intonation" = "漢語弁音 (ローマ字+数字音調)";
"Horizontal" = "横型陳列";
"Hsu" = "許氏国音自然配列";
"Hualuo Pinyin with Numeral Intonation" = "中華ローマ弁音 (ローマ字+数字音調)";
"IBM" = "IBM 配列";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "単語の前で // macOS 内蔵注音入力のやり方";
"Japanese" = "和語";
"Keyboard" = "配列設定";
"Misc Settings:" = "他の設定:";
@ -132,6 +136,7 @@
"Output Settings:" = "出力設定:";
"Phonetic Parser:" = "注音配列:";
"Push the cursor in front of the phrase after selection" = "候補選択の直後、すぐカーソルを単語の向こうに推し進める";
"Secondary Pinyin with Numeral Intonation" = "国音二式 (ローマ字+数字音調)";
"Selection Keys:" = "言選り用キー:";
"Show Hanyu-Pinyin in the inline composition buffer" = "弁音合併入力(入力緩衝列で代わりに漢語弁音の音読み)";
"Show page buttons in candidate window" = "入力候補陳列の側にページボタンを表示";
@ -140,10 +145,10 @@
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+Space で次のページ、Space で次の候補文字を";
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space で次のページ、Shift+Space で次の候補文字を";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "マナーモード // 外すと入力間違った時に変な声が出る";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "単語の前で // macOS 内蔵注音入力のやり方";
"at anyplace else (like Windows Yahoo KeyKey)" = "単語の中・後で // Windows Yahoo KeyKey のやり方";
"Traditional Chinese" = "繁体中国語";
"Typing Style:" = "入力習慣:";
"UI Language:" = "表示用言語:";
"Universal Pinyin with Numeral Intonation" = "汎用弁音 (ローマ字+数字音調)";
"Use ESC key to clear the entire input buffer" = "ESC キーで入力緩衝列を消す";
"Vertical" = "縦型陳列";
"Yale Pinyin with Numeral Intonation" = "イェール弁音 (ローマ字+数字音調)";

View File

@ -85,6 +85,7 @@
"Apple Chewing - Dachen" = "Apple 大千注音键盘排列";
"Apple Chewing - Eten Traditional" = "Apple 倚天传统键盘排列";
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器得配置为大千排列。";
"at anyplace else (like Windows Yahoo KeyKey)" = "将游标置于词语中后方 // Windows 奇摩注音风格";
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自动将繁体中文字转为日文 JIS 新字体";
"Auto-convert traditional Chinese glyphs to KangXi characters" = "自动将繁体中文字转为康熙正体字";
"Automatically reload user data files if changes detected" = "自动检测并载入使用者语汇档案变更";
@ -104,6 +105,7 @@
"Choose your preferred layout of the candidate window." = "选择您所偏好的候选字窗布局。";
"Cursor Selection:" = "选字游标:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微软标准/王安/零壹/仲鼎/国乔)";
"Dachen 26 (libChewing)" = "酷音大千二十六键";
"Debug Mode" = "侦错模式";
"Dictionary" = "辞典";
"Emulating select-candidate-per-character mode" = "模拟 90 年代前期注音逐字选字输入风格";
@ -122,7 +124,10 @@
"Hanyu Pinyin with Numeral Intonation" = "汉语拼音+数字标调";
"Horizontal" = "横向布局";
"Hsu" = "许氏国音自然排列";
"Hualuo Pinyin with Numeral Intonation" = "华罗拼音+数字标调";
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+数字标调";
"IBM" = "IBM 排列";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "将游标置于词语前方 // macOS 内建注音风格";
"Japanese" = "和语";
"Keyboard" = "键盘";
"Misc Settings:" = "杂项:";
@ -132,6 +137,7 @@
"Output Settings:" = "输出设定:";
"Phonetic Parser:" = "注音排列:";
"Push the cursor in front of the phrase after selection" = "在选字后将游标置于该字词的前方";
"Secondary Pinyin with Numeral Intonation" = "国音二式+数字标调";
"Selection Keys:" = "选字键:";
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音并击模式(组字区内看到的是汉语拼音)";
"Show page buttons in candidate window" = "在选字窗内显示翻页按钮";
@ -140,10 +146,11 @@
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格键 换下一页,空格键 换选下一个后选字";
"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格键 换下一页Shift+空格键 换选下一个后选字";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉耻模式 // 取消勾选的话,敲错字时会有异音";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "将游标置于词语前方 // macOS 内建注音风格";
"at anyplace else (like Windows Yahoo KeyKey)" = "将游标置于词语中后方 // Windows 奇摩注音风格";
"Traditional Chinese" = "繁体中文";
"Typing Style:" = "输入风格:";
"UI Language:" = "介面语言:";
"Universal Pinyin with Numeral Intonation" = "通用拼音+数字标调";
"Universal Pinyin with Numeral Intonation" = "通用拼音+数字标调";
"Use ESC key to clear the entire input buffer" = "敲 ESC 键以清空整个组字缓冲区";
"Vertical" = "纵向布局";
"Yale Pinyin with Numeral Intonation" = "耶鲁拼音+数字标调";

View File

@ -85,6 +85,7 @@
"Apple Chewing - Dachen" = "Apple 大千注音鍵盤佈局";
"Apple Chewing - Eten Traditional" = "Apple 倚天傳統鍵盤佈局";
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器得配置為大千排列。";
"at anyplace else (like Windows Yahoo KeyKey)" = "將游標置於詞語中後方 // Windows 奇摩注音風格";
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自動將繁體中文字轉為日文 JIS 新字體";
"Auto-convert traditional Chinese glyphs to KangXi characters" = "自動將繁體中文字轉為康熙正體字";
"Automatically reload user data files if changes detected" = "自動檢測並載入使用者語彙檔案變更";
@ -104,6 +105,7 @@
"Choose your preferred layout of the candidate window." = "選擇您所偏好的候選字窗佈局。";
"Cursor Selection:" = "選字游標:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微軟標準/王安/零壹/仲鼎/國喬)";
"Dachen 26 (libChewing)" = "酷音大千二十六鍵";
"Debug Mode" = "偵錯模式";
"Dictionary" = "辭典";
"Emulating select-candidate-per-character mode" = "模擬 90 年代前期注音逐字選字輸入風格";
@ -122,7 +124,9 @@
"Hanyu Pinyin with Numeral Intonation" = "漢語拼音+數字標調";
"Horizontal" = "橫向佈局";
"Hsu" = "許氏國音自然排列";
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+數字標調";
"IBM" = "IBM 排列";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "將游標置於詞語前方 // macOS 內建注音風格";
"Japanese" = "和語";
"Keyboard" = "鍵盤";
"Misc Settings:" = "雜項:";
@ -132,6 +136,7 @@
"Output Settings:" = "輸出設定:";
"Phonetic Parser:" = "注音排列:";
"Push the cursor in front of the phrase after selection" = "在選字後將游標置於該字詞的前方";
"Secondary Pinyin with Numeral Intonation" = "國音二式+數字標調";
"Selection Keys:" = "選字鍵:";
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音並擊模式(組字區內看到的是漢語拼音)";
"Show page buttons in candidate window" = "在選字窗內顯示翻頁按鈕";
@ -140,10 +145,10 @@
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格鍵 換下一頁,空格鍵 換選下一個後選字";
"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格鍵 換下一頁Shift+空格鍵 換選下一個後選字";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "將游標置於詞語前方 // macOS 內建注音風格";
"at anyplace else (like Windows Yahoo KeyKey)" = "將游標置於詞語中後方 // Windows 奇摩注音風格";
"Traditional Chinese" = "繁體中文";
"Typing Style:" = "輸入風格:";
"UI Language:" = "介面語言:";
"Universal Pinyin with Numeral Intonation" = "通用拼音+數字標調";
"Use ESC key to clear the entire input buffer" = "敲 ESC 鍵以清空整個組字緩衝區";
"Vertical" = "縱向佈局";
"Yale Pinyin with Numeral Intonation" = "耶魯拼音+數字標調";

View File

@ -45,20 +45,60 @@ struct suiPrefPaneKeyboard: View {
var body: some View {
Preferences.Container(contentWidth: contentWidth) {
Preferences.Section(label: { Text(LocalizedStringKey("Phonetic Parser:")) }) {
Picker("", selection: $selMandarinParser) {
Text(LocalizedStringKey("Dachen (Microsoft Standard / Wang / 01, etc.)")).tag(0)
Text(LocalizedStringKey("Eten Traditional")).tag(1)
Text(LocalizedStringKey("Eten 26")).tag(3)
Text(LocalizedStringKey("IBM")).tag(4)
Text(LocalizedStringKey("Hsu")).tag(2)
Text(LocalizedStringKey("MiTAC")).tag(5)
Text(LocalizedStringKey("Fake Seigyou")).tag(6)
// Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10)
}.onChange(of: selMandarinParser) { value in
mgrPrefs.mandarinParser = value
HStack {
Picker("", selection: $selMandarinParser) {
Group {
Text(LocalizedStringKey("Dachen (Microsoft Standard / Wang / 01, etc.)")).tag(0)
Text(LocalizedStringKey("Dachen 26 (libChewing)")).tag(7)
Text(LocalizedStringKey("Eten Traditional")).tag(1)
Text(LocalizedStringKey("Eten 26")).tag(3)
Text(LocalizedStringKey("IBM")).tag(4)
Text(LocalizedStringKey("Hsu")).tag(2)
Text(LocalizedStringKey("MiTAC")).tag(5)
Text(LocalizedStringKey("Fake Seigyou")).tag(6)
}
Divider()
Group {
Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10)
Text(LocalizedStringKey("Secondary Pinyin with Numeral Intonation")).tag(11)
Text(LocalizedStringKey("Yale Pinyin with Numeral Intonation")).tag(12)
Text(LocalizedStringKey("Hualuo Pinyin with Numeral Intonation")).tag(13)
Text(LocalizedStringKey("Universal Pinyin with Numeral Intonation")).tag(14)
}
}.onChange(of: selMandarinParser) { value in
mgrPrefs.mandarinParser = value
switch value {
case 0:
if !AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
}
default:
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
}
}
}
.labelsHidden()
Button {
mgrPrefs.mandarinParser = 0
selMandarinParser = mgrPrefs.mandarinParser
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
} label: {
Text("↻ㄅ")
}
Button {
mgrPrefs.mandarinParser = 10
selMandarinParser = mgrPrefs.mandarinParser
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
} label: {
Text("↻A")
}
}
.labelsHidden()
.frame(width: 320.0)
.frame(width: 380.0)
Text(LocalizedStringKey("Choose the phonetic layout for Mandarin parser."))
.preferenceDescription()
}
@ -71,6 +111,10 @@ struct suiPrefPaneKeyboard: View {
}.id(UUID())
}.onChange(of: selBasicKeyboardLayout) { value in
mgrPrefs.basicKeyboardLayout = value
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(value) {
mgrPrefs.mandarinParser = 0
selMandarinParser = mgrPrefs.mandarinParser
}
}
.labelsHidden()
.frame(width: 240.0)

View File

@ -782,12 +782,18 @@
<menu key="menu" title="OtherViews" id="5">
<items>
<menuItem title="Standard" state="on" id="6"/>
<menuItem title="Dachen 26" tag="7" id="xjP-r7-GaK"/>
<menuItem title="ETen" tag="1" id="7"/>
<menuItem title="ETen26" tag="3" id="9"/>
<menuItem title="IBM" tag="4" id="137"/>
<menuItem title="Hsu" tag="2" id="8"/>
<menuItem title="MiTAC" tag="5" id="7fV-x8-WHQ"/>
<menuItem title="Fake Seigyou" tag="6" id="27F-8T-FkQ"/>
<menuItem title="Hanyu Pinyin" tag="10" id="10"/>
<menuItem title="Secondary Pinyin" tag="11" id="Parser11"/>
<menuItem title="Yale Pinyin" tag="12" id="Parser12"/>
<menuItem title="Hualuo Pinyin" tag="13" id="Parser13"/>
<menuItem title="Universal Pinyin" tag="14" id="Parser14"/>
</items>
</menu>
<connections>

View File

@ -20,8 +20,8 @@
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
"9.title" = "ETen26";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
"10.title" = "Hanyu Pinyin";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
"10.title" = "Hanyu Pinyin with Numeral Intonation";
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
"12.title" = "BPMF Parser:";
@ -232,3 +232,18 @@
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
"iWy-Nw-QKB.title" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
"xjP-r7-GaK.title" = "Dachen 26 (libChewing)";
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
"Parser11.title" = "Secondary Pinyin with Numeral Intonation";
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
"Parser12.title" = "Yale Pinyin with Numeral Intonation";
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
"Parser13.title" = "Hualuo Pinyin with Numeral Intonation";
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
"Parser14.title" = "Universal Pinyin with Numeral Intonation";

View File

@ -20,7 +20,7 @@
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
"9.title" = "倚天形忘れ配列 (26キー)";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
"10.title" = "漢語弁音(ローマ字+数字音調)";
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
@ -232,3 +232,18 @@
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter で出すのを漢語弁音と変換";
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
"xjP-r7-GaK.title" = "酷音大千 26 キー配列";
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
"Parser11.title" = "国音二式 (ローマ字+数字音調)";
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
"Parser12.title" = "イェール弁音 (ローマ字+数字音調)";
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
"Parser13.title" = "中華ローマ弁音 (ローマ字+数字音調)";
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
"Parser14.title" = "汎用弁音 (ローマ字+数字音調)";

View File

@ -20,8 +20,8 @@
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
"9.title" = "倚天二十六键";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
"10.title" = "汉语拼音二式(字母拼音+数字标调)";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
"10.title" = "汉语拼音+数字标调";
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
"12.title" = "基础键盘布局:";
@ -232,3 +232,18 @@
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 输出汉语拼音而非注音";
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
"xjP-r7-GaK.title" = "酷音大千二十六键";
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
"Parser11.title" = "国音二式+数字标调";
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
"Parser12.title" = "耶鲁拼音+数字标调";
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
"Parser13.title" = "华罗拼音+数字标调";
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
"Parser14.title" = "通用拼音+数字标调";

View File

@ -20,8 +20,8 @@
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
"9.title" = "倚天二十六鍵";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
"10.title" = "漢語拼音二式(字母拼音+數字標調)";
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
"10.title" = "漢語拼音+數字標調";
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
"12.title" = "注音排列:";
@ -232,3 +232,18 @@
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 輸出漢語拼音而非注音";
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
"xjP-r7-GaK.title" = "酷音大千二十六鍵";
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
"Parser11.title" = "國音二式+數字標調";
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
"Parser12.title" = "耶魯拼音+數字標調";
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
"Parser13.title" = "華羅拼音+數字標調";
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
"Parser14.title" = "通用拼音+數字標調";

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>1.5.8</string>
<string>1.5.9</string>
<key>CFBundleVersion</key>
<string>1958</string>
<string>1959</string>
<key>UpdateInfoEndpoint</key>
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
<key>UpdateInfoSite</key>

View File

@ -726,7 +726,7 @@
<key>USE_HFS+_COMPRESSION</key>
<false/>
<key>VERSION</key>
<string>1.5.8</string>
<string>1.5.9</string>
</dict>
<key>TYPE</key>
<integer>0</integer>

View File

@ -318,8 +318,6 @@
D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = main.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlPrefWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D47F7DCF278C0897002F9DD7 /* ctlNonModalAlertWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlNonModalAlertWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = UserOverrideModel.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = UserOverrideModel.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
D4A13D5927A59D5C003BE359 /* ctlInputMethod.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlInputMethod.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D4E33D8927A838CF006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
D4E33D8E27A838F0006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@ -470,7 +468,6 @@
5B62A32427AE757300A19448 /* LangModelRelated */ = {
isa = PBXGroup;
children = (
5B62A32527AE758000A19448 /* OldFileReferences */,
5B407308281672610023DFFF /* SubLMs */,
5B949BDA2816DDBC00D87B5D /* LMConsolidator.swift */,
5BD0113A28180D6100609769 /* LMInstantiator.swift */,
@ -479,15 +476,6 @@
path = LangModelRelated;
sourceTree = "<group>";
};
5B62A32527AE758000A19448 /* OldFileReferences */ = {
isa = PBXGroup;
children = (
D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */,
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */,
);
path = OldFileReferences;
sourceTree = "<group>";
};
5B62A33027AE78E500A19448 /* Resources */ = {
isa = PBXGroup;
children = (
@ -1308,7 +1296,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1958;
CURRENT_PROJECT_VERSION = 1959;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
@ -1331,7 +1319,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.8;
MARKETING_VERSION = 1.5.9;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1364,7 +1352,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1958;
CURRENT_PROJECT_VERSION = 1959;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -1383,7 +1371,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.8;
MARKETING_VERSION = 1.5.9;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1498,7 +1486,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1958;
CURRENT_PROJECT_VERSION = 1959;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1533,7 +1521,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.8;
MARKETING_VERSION = 1.5.9;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1565,7 +1553,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1958;
CURRENT_PROJECT_VERSION = 1959;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1595,7 +1583,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.8;
MARKETING_VERSION = 1.5.9;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1678,7 +1666,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1958;
CURRENT_PROJECT_VERSION = 1959;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
@ -1703,7 +1691,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.8;
MARKETING_VERSION = 1.5.9;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1730,7 +1718,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1958;
CURRENT_PROJECT_VERSION = 1959;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1750,7 +1738,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.8;
MARKETING_VERSION = 1.5.9;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";