MainAssembly // + Candidate Service (Menu & Editor).
This commit is contained in:
parent
dc79c629a1
commit
5eec7cd604
|
@ -200,7 +200,8 @@ public extension IMEState {
|
||||||
case .ofCandidates where cursor != marker: return data.attributedStringMarking(for: session)
|
case .ofCandidates where cursor != marker: return data.attributedStringMarking(for: session)
|
||||||
case .ofCandidates where cursor == marker: break
|
case .ofCandidates where cursor == marker: break
|
||||||
case .ofAssociates: return data.attributedStringPlaceholder(for: session)
|
case .ofAssociates: return data.attributedStringPlaceholder(for: session)
|
||||||
case .ofSymbolTable where displayedText.isEmpty: return data.attributedStringPlaceholder(for: session)
|
case .ofSymbolTable where displayedText.isEmpty || node.containsCandidateServices:
|
||||||
|
return data.attributedStringPlaceholder(for: session)
|
||||||
case .ofSymbolTable where !displayedText.isEmpty: break
|
case .ofSymbolTable where !displayedText.isEmpty: break
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,7 @@ extension InputHandler {
|
||||||
delegate.candidateSelectionConfirmedByInputHandler(at: ctlCandidate.highlightedIndex)
|
delegate.candidateSelectionConfirmedByInputHandler(at: ctlCandidate.highlightedIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let highlightedCandidate = state.candidates[ctlCandidate.highlightedIndex] // 關聯詞語功能專用。
|
||||||
if let keyCodeType = KeyCode(rawValue: input.keyCode) {
|
if let keyCodeType = KeyCode(rawValue: input.keyCode) {
|
||||||
switch keyCodeType {
|
switch keyCodeType {
|
||||||
case .kLineFeed, .kCarriageReturn:
|
case .kLineFeed, .kCarriageReturn:
|
||||||
|
@ -101,7 +102,6 @@ extension InputHandler {
|
||||||
delegate.switchState(IMEState.ofAbortion())
|
delegate.switchState(IMEState.ofAbortion())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let highlightedCandidate = state.candidates[ctlCandidate.highlightedIndex] // 關聯詞語功能專用。
|
|
||||||
var handleAssociates = !prefs.useSCPCTypingMode && prefs.associatedPhrasesEnabled // 關聯詞語功能專用。
|
var handleAssociates = !prefs.useSCPCTypingMode && prefs.associatedPhrasesEnabled // 關聯詞語功能專用。
|
||||||
handleAssociates = handleAssociates && compositor.cursor == compositor.length // 關聯詞語功能專用。
|
handleAssociates = handleAssociates && compositor.cursor == compositor.length // 關聯詞語功能專用。
|
||||||
confirmHighlightedCandidate()
|
confirmHighlightedCandidate()
|
||||||
|
@ -336,9 +336,17 @@ extension InputHandler {
|
||||||
// MARK: - Flipping pages by using symbol menu keys (when they are not occupied).
|
// MARK: - Flipping pages by using symbol menu keys (when they are not occupied).
|
||||||
|
|
||||||
if input.isSymbolMenuPhysicalKey {
|
if input.isSymbolMenuPhysicalKey {
|
||||||
|
let candidateTextServiceMenuRunning = state.node.containsCandidateServices && state.type == .ofSymbolTable
|
||||||
switch input.commonKeyModifierFlags {
|
switch input.commonKeyModifierFlags {
|
||||||
case .shift, [],
|
case .shift, [],
|
||||||
.option where state.type != .ofSymbolTable:
|
.option where !candidateTextServiceMenuRunning:
|
||||||
|
if !candidateTextServiceMenuRunning {
|
||||||
|
let handled = handleServiceMenuInitiation(
|
||||||
|
candidateText: highlightedCandidate.value,
|
||||||
|
reading: highlightedCandidate.keyArray
|
||||||
|
)
|
||||||
|
if handled { return true }
|
||||||
|
}
|
||||||
var updated = true
|
var updated = true
|
||||||
let reverseTrigger = input.isShiftHold || input.isOptionHold
|
let reverseTrigger = input.isShiftHold || input.isOptionHold
|
||||||
updated = reverseTrigger ? ctlCandidate.showPreviousLine() : ctlCandidate.showNextLine()
|
updated = reverseTrigger ? ctlCandidate.showPreviousLine() : ctlCandidate.showNextLine()
|
||||||
|
|
|
@ -898,6 +898,20 @@ extension InputHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - 處理選字窗服務選單 (Service Menu)
|
||||||
|
|
||||||
|
func handleServiceMenuInitiation(candidateText: String, reading: [String]) -> Bool {
|
||||||
|
guard let delegate = delegate, delegate.state.type != .ofDeactivated else { return false }
|
||||||
|
guard !candidateText.isEmpty else { return false }
|
||||||
|
let rootNode = CandidateTextService.getCurrentServiceMenu(candidate: candidateText, reading: reading)
|
||||||
|
guard let rootNode = rootNode else { return false }
|
||||||
|
// 得在這裡先 commit buffer,不然會導致「在摁 ESC 離開符號選單時會重複輸入上一次的組字區的內容」的不當行為。
|
||||||
|
let textToCommit = generateStateOfInputting(sansReading: true).displayedText
|
||||||
|
delegate.switchState(IMEState.ofCommitting(textToCommit: textToCommit))
|
||||||
|
delegate.switchState(IMEState.ofSymbolTable(node: rootNode))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - 處理 Caps Lock 與英數輸入模式(Caps Lock and Alphanumerical mode)
|
// MARK: - 處理 Caps Lock 與英數輸入模式(Caps Lock and Alphanumerical mode)
|
||||||
|
|
||||||
/// 處理 CapsLock 與英數輸入模式。
|
/// 處理 CapsLock 與英數輸入模式。
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
|
// ====================
|
||||||
|
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||||
|
// ... with NTL restriction stating that:
|
||||||
|
// No trademark license is granted to use the trade names, trademarks, service
|
||||||
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public class CtlServiceMenuEditor: NSWindowController {
|
||||||
|
let viewController = VwrServiceMenuEditor()
|
||||||
|
|
||||||
|
public static var shared: CtlServiceMenuEditor?
|
||||||
|
public init() {
|
||||||
|
super.init(
|
||||||
|
window: .init(
|
||||||
|
contentRect: CGRect(x: 401, y: 295, width: 770, height: 335),
|
||||||
|
styleMask: [.titled, .closable, .miniaturizable],
|
||||||
|
backing: .buffered,
|
||||||
|
defer: true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
viewController.windowController = self
|
||||||
|
viewController.loadView()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func show() {
|
||||||
|
if shared == nil {
|
||||||
|
shared = CtlServiceMenuEditor()
|
||||||
|
}
|
||||||
|
guard let shared = shared, let sharedWindow = shared.window else { return }
|
||||||
|
if !sharedWindow.isVisible {
|
||||||
|
shared.windowDidLoad()
|
||||||
|
}
|
||||||
|
sharedWindow.setPosition(vertical: .center, horizontal: .right, padding: 20)
|
||||||
|
sharedWindow.orderFrontRegardless() // 逼著視窗往最前方顯示
|
||||||
|
sharedWindow.title = "Service Menu Editor".localized
|
||||||
|
sharedWindow.level = .statusBar
|
||||||
|
if #available(macOS 10.10, *) {
|
||||||
|
sharedWindow.titlebarAppearsTransparent = true
|
||||||
|
}
|
||||||
|
shared.showWindow(shared)
|
||||||
|
NSApp.popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func windowDidLoad() {
|
||||||
|
super.windowDidLoad()
|
||||||
|
let view = viewController.view
|
||||||
|
window?.contentView = view
|
||||||
|
if let window = window {
|
||||||
|
var frame = window.frame
|
||||||
|
frame.size = view.fittingSize
|
||||||
|
window.setFrame(frame, display: true)
|
||||||
|
}
|
||||||
|
window?.setPosition(vertical: .center, horizontal: .right, padding: 20)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,368 @@
|
||||||
|
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
|
// ====================
|
||||||
|
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||||
|
// ... with NTL restriction stating that:
|
||||||
|
// No trademark license is granted to use the trade names, trademarks, service
|
||||||
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import CocoaExtension
|
||||||
|
import Foundation
|
||||||
|
import Shared
|
||||||
|
|
||||||
|
public class VwrServiceMenuEditor: NSViewController {
|
||||||
|
let windowWidth: CGFloat = 770
|
||||||
|
let contentWidth: CGFloat = 750
|
||||||
|
let tableHeight: CGFloat = 230
|
||||||
|
|
||||||
|
lazy var tblServices: NSTableView = .init()
|
||||||
|
lazy var btnShowInstructions = NSButton("How to Fill", target: self, action: #selector(btnShowInstructionsClicked(_:)))
|
||||||
|
lazy var btnAddService = NSFileDragRetrieverButton(
|
||||||
|
"Add Service",
|
||||||
|
target: self,
|
||||||
|
action: #selector(btnAddServiceClicked(_:)),
|
||||||
|
postDrag: handleDrag
|
||||||
|
)
|
||||||
|
lazy var btnRemoveService = NSButton("Remove Selected", target: self, action: #selector(btnRemoveServiceClicked(_:)))
|
||||||
|
lazy var btnResetService = NSButton("Reset Default", target: self, action: #selector(btnResetServiceClicked(_:)))
|
||||||
|
lazy var btnCopyAllToClipboard = NSButton("Copy All to Clipboard", target: self, action: #selector(btnCopyAllToClipboardClicked(_:)))
|
||||||
|
lazy var tableColumn1Cell = NSTextFieldCell()
|
||||||
|
lazy var tableColumn1 = NSTableColumn()
|
||||||
|
lazy var tableColumn2Cell = NSTextFieldCell()
|
||||||
|
lazy var tableColumn2 = NSTableColumn()
|
||||||
|
|
||||||
|
var windowController: NSWindowController?
|
||||||
|
|
||||||
|
public convenience init(windowController: NSWindowController? = nil) {
|
||||||
|
self.init()
|
||||||
|
self.windowController = windowController
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func loadView() {
|
||||||
|
tblServices.reloadData()
|
||||||
|
view = body ?? .init()
|
||||||
|
(view as? NSStackView)?.alignment = .centerX
|
||||||
|
view.makeSimpleConstraint(.width, relation: .equal, value: windowWidth)
|
||||||
|
btnRemoveService.keyEquivalent = .init(NSEvent.SpecialKey.delete.unicodeScalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: NSView? {
|
||||||
|
NSStackView.build(.vertical, insets: .new(all: 14)) {
|
||||||
|
NSStackView.build(.horizontal) {
|
||||||
|
btnAddService
|
||||||
|
btnRemoveService
|
||||||
|
btnCopyAllToClipboard
|
||||||
|
btnShowInstructions
|
||||||
|
NSView()
|
||||||
|
btnResetService
|
||||||
|
}
|
||||||
|
makeScrollableTable()
|
||||||
|
.makeSimpleConstraint(.height, relation: .equal, value: tableHeight)
|
||||||
|
NSStackView.build(.horizontal) {
|
||||||
|
let descriptionWidth = contentWidth - 10
|
||||||
|
NSStackView.build(.vertical) {
|
||||||
|
let strDescription = "i18n:CandidateServiceMenuEditor.description"
|
||||||
|
strDescription.makeNSLabel(descriptive: true, fixWidth: descriptionWidth)
|
||||||
|
.makeSimpleConstraint(.width, relation: .greaterThanOrEqual, value: descriptionWidth)
|
||||||
|
NSView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeScrollableTable() -> NSScrollView {
|
||||||
|
let scrollContainer = NSScrollView()
|
||||||
|
scrollContainer.scrollerStyle = .legacy
|
||||||
|
scrollContainer.autohidesScrollers = true
|
||||||
|
scrollContainer.documentView = tblServices
|
||||||
|
scrollContainer.hasVerticalScroller = true
|
||||||
|
scrollContainer.hasHorizontalScroller = true
|
||||||
|
if #available(macOS 11.0, *) {
|
||||||
|
tblServices.style = .inset
|
||||||
|
}
|
||||||
|
tblServices.addTableColumn(tableColumn1)
|
||||||
|
tblServices.addTableColumn(tableColumn2)
|
||||||
|
// tblServices.headerView = nil
|
||||||
|
tblServices.delegate = self
|
||||||
|
tblServices.allowsExpansionToolTips = true
|
||||||
|
tblServices.allowsMultipleSelection = true
|
||||||
|
tblServices.autoresizingMask = [.width, .height]
|
||||||
|
tblServices.autosaveTableColumns = false
|
||||||
|
tblServices.backgroundColor = NSColor.controlBackgroundColor
|
||||||
|
tblServices.columnAutoresizingStyle = .lastColumnOnlyAutoresizingStyle
|
||||||
|
tblServices.frame = CGRect(x: 0, y: 0, width: 728, height: tableHeight)
|
||||||
|
tblServices.gridColor = NSColor.clear
|
||||||
|
tblServices.intercellSpacing = CGSize(width: 15, height: 0)
|
||||||
|
tblServices.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||||
|
tblServices.registerForDraggedTypes([.kUTTypeData, .kUTTypeFileURL])
|
||||||
|
tblServices.dataSource = self
|
||||||
|
tblServices.target = self
|
||||||
|
if #available(macOS 11.0, *) { tblServices.style = .inset }
|
||||||
|
|
||||||
|
tableColumn1.identifier = NSUserInterfaceItemIdentifier("colTitle")
|
||||||
|
tableColumn1.headerCell.title = "i18n:CandidateServiceMenuEditor.table.field.MenuTitle".localized
|
||||||
|
tableColumn1.maxWidth = 280
|
||||||
|
tableColumn1.minWidth = 200
|
||||||
|
tableColumn1.resizingMask = [.autoresizingMask, .userResizingMask]
|
||||||
|
tableColumn1.width = 200
|
||||||
|
tableColumn1.dataCell = tableColumn1Cell
|
||||||
|
|
||||||
|
tableColumn1Cell.font = NSFont.systemFont(ofSize: 13)
|
||||||
|
tableColumn1Cell.isEditable = true
|
||||||
|
tableColumn1Cell.isSelectable = true
|
||||||
|
tableColumn1Cell.lineBreakMode = .byTruncatingTail
|
||||||
|
tableColumn1Cell.stringValue = "Text Cell"
|
||||||
|
tableColumn1Cell.textColor = NSColor.controlTextColor
|
||||||
|
|
||||||
|
tableColumn2.identifier = NSUserInterfaceItemIdentifier("colValue")
|
||||||
|
tableColumn2.headerCell.title = "i18n:CandidateServiceMenuEditor.table.field.Value".localized
|
||||||
|
tableColumn2.maxWidth = 1000
|
||||||
|
tableColumn2.minWidth = 40
|
||||||
|
tableColumn2.resizingMask = [.autoresizingMask, .userResizingMask]
|
||||||
|
tableColumn2.width = 480
|
||||||
|
tableColumn2.dataCell = tableColumn2Cell
|
||||||
|
|
||||||
|
tableColumn2Cell.backgroundColor = NSColor.controlBackgroundColor
|
||||||
|
tableColumn2Cell.font = NSFont.systemFont(ofSize: 13)
|
||||||
|
tableColumn2Cell.isEditable = true
|
||||||
|
tableColumn2Cell.isSelectable = true
|
||||||
|
tableColumn2Cell.lineBreakMode = .byTruncatingTail
|
||||||
|
tableColumn2Cell.stringValue = "Text Cell"
|
||||||
|
tableColumn2Cell.textColor = NSColor.controlTextColor
|
||||||
|
|
||||||
|
return scrollContainer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - UserDefaults Handlers.
|
||||||
|
|
||||||
|
public extension VwrServiceMenuEditor {
|
||||||
|
static var servicesList: [CandidateTextService] {
|
||||||
|
get {
|
||||||
|
PrefMgr.shared.candidateServiceMenuContents.parseIntoCandidateTextServiceStack()
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
PrefMgr.shared.candidateServiceMenuContents = newValue.rawRepresentation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func removeService(at index: Int) {
|
||||||
|
guard index < Self.servicesList.count else { return }
|
||||||
|
Self.servicesList.remove(at: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Common Operation Methods.
|
||||||
|
|
||||||
|
extension VwrServiceMenuEditor {
|
||||||
|
func refresh() {
|
||||||
|
tblServices.reloadData()
|
||||||
|
reassureButtonAvailability()
|
||||||
|
}
|
||||||
|
|
||||||
|
func reassureButtonAvailability() {
|
||||||
|
btnRemoveService.isEnabled = (0 ..< Self.servicesList.count).contains(
|
||||||
|
tblServices.selectedRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleDrag(_ givenURL: URL) {
|
||||||
|
guard let string = try? String(contentsOf: givenURL) else { return }
|
||||||
|
Self.servicesList.append(contentsOf: string.components(separatedBy: .newlines).parseIntoCandidateTextServiceStack())
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - IBActions.
|
||||||
|
|
||||||
|
extension VwrServiceMenuEditor {
|
||||||
|
@IBAction func btnShowInstructionsClicked(_: Any) {
|
||||||
|
let strTitle = "How to Fill".localized
|
||||||
|
let strFillGuide = "i18n:CandidateServiceMenuEditor.formatGuide".localized
|
||||||
|
windowController?.window.callAlert(title: strTitle, text: strFillGuide)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func btnResetServiceClicked(_: Any) {
|
||||||
|
PrefMgr.shared.candidateServiceMenuContents = PrefMgr.kDefaultCandidateServiceMenuItem
|
||||||
|
tblServices.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func btnCopyAllToClipboardClicked(_: Any) {
|
||||||
|
var resultArrayLines = [String]()
|
||||||
|
Self.servicesList.forEach { currentService in
|
||||||
|
resultArrayLines.append("\(currentService.key)\t\(currentService.definedValue)")
|
||||||
|
}
|
||||||
|
let result = resultArrayLines.joined(separator: "\n").appending("\n")
|
||||||
|
NSPasteboard.general.declareTypes([.string], owner: nil)
|
||||||
|
NSPasteboard.general.setString(result, forType: .string)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func btnRemoveServiceClicked(_: Any) {
|
||||||
|
guard let minIndexSelected = tblServices.selectedRowIndexes.min() else { return }
|
||||||
|
if minIndexSelected >= Self.servicesList.count { return }
|
||||||
|
if minIndexSelected < 0 { return }
|
||||||
|
var isLastRow = false
|
||||||
|
tblServices.selectedRowIndexes.sorted().reversed().forEach { index in
|
||||||
|
isLastRow = {
|
||||||
|
if Self.servicesList.count < 2 { return false }
|
||||||
|
return minIndexSelected == Self.servicesList.count - 1
|
||||||
|
}()
|
||||||
|
if index < Self.servicesList.count {
|
||||||
|
Self.removeService(at: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isLastRow {
|
||||||
|
tblServices.selectRowIndexes(.init(arrayLiteral: minIndexSelected - 1), byExtendingSelection: false)
|
||||||
|
}
|
||||||
|
tblServices.reloadData()
|
||||||
|
btnRemoveService.isEnabled = (0 ..< Self.servicesList.count).contains(minIndexSelected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func btnAddServiceClicked(_: Any) {
|
||||||
|
guard let window = windowController?.window else { return }
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = NSLocalizedString(
|
||||||
|
"i18n:CandidateServiceMenuEditor.prompt", comment: ""
|
||||||
|
)
|
||||||
|
alert.informativeText = NSLocalizedString(
|
||||||
|
"i18n:CandidateServiceMenuEditor.howToGetGuide", comment: ""
|
||||||
|
)
|
||||||
|
alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
||||||
|
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
|
||||||
|
|
||||||
|
let maxFloat = Double(Float.greatestFiniteMagnitude)
|
||||||
|
let scrollview = NSScrollView(frame: NSRect(x: 0, y: 0, width: 512, height: 200))
|
||||||
|
let contentSize = scrollview.contentSize
|
||||||
|
scrollview.borderType = .noBorder
|
||||||
|
scrollview.hasVerticalScroller = true
|
||||||
|
scrollview.hasHorizontalScroller = true
|
||||||
|
scrollview.horizontalScroller?.scrollerStyle = .legacy
|
||||||
|
scrollview.verticalScroller?.scrollerStyle = .legacy
|
||||||
|
scrollview.autoresizingMask = [.width, .height]
|
||||||
|
let theTextView = NSTextView(frame: NSRect(x: 0, y: 0, width: contentSize.width, height: contentSize.height))
|
||||||
|
scrollview.documentView = theTextView
|
||||||
|
theTextView.minSize = NSSize(width: 0.0, height: contentSize.height)
|
||||||
|
theTextView.maxSize = NSSize(width: maxFloat, height: maxFloat)
|
||||||
|
theTextView.isVerticallyResizable = true
|
||||||
|
theTextView.isHorizontallyResizable = false
|
||||||
|
theTextView.autoresizingMask = .width
|
||||||
|
theTextView.textContainer?.containerSize = NSSize(width: contentSize.width, height: maxFloat)
|
||||||
|
theTextView.textContainer?.widthTracksTextView = true
|
||||||
|
theTextView.enclosingScrollView?.hasHorizontalScroller = true
|
||||||
|
theTextView.isHorizontallyResizable = true
|
||||||
|
theTextView.autoresizingMask = [.width, .height]
|
||||||
|
theTextView.textContainer?.containerSize = NSSize(width: maxFloat, height: maxFloat)
|
||||||
|
theTextView.textContainer?.widthTracksTextView = false
|
||||||
|
theTextView.toolTip = "i18n:CandidateServiceMenuEditor.formatGuide".localized
|
||||||
|
|
||||||
|
alert.accessoryView = scrollview
|
||||||
|
alert.beginSheetModal(at: window) { result in
|
||||||
|
switch result {
|
||||||
|
case .alertFirstButtonReturn:
|
||||||
|
let rawLines = theTextView.textContainer?.textView?.string.components(separatedBy: .newlines) ?? []
|
||||||
|
self.tblServices.beginUpdates()
|
||||||
|
Self.servicesList.append(contentsOf: rawLines.parseIntoCandidateTextServiceStack())
|
||||||
|
self.tblServices.endUpdates()
|
||||||
|
default: return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - TableView Extensions.
|
||||||
|
|
||||||
|
extension VwrServiceMenuEditor: NSTableViewDelegate, NSTableViewDataSource {
|
||||||
|
public func numberOfRows(in _: NSTableView) -> Int {
|
||||||
|
Self.servicesList.count
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tableView(_: NSTableView, shouldEdit _: NSTableColumn?, row _: Int) -> Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tableView(_: NSTableView, objectValueFor column: NSTableColumn?, row: Int) -> Any? {
|
||||||
|
defer {
|
||||||
|
self.btnRemoveService.isEnabled = (0 ..< Self.servicesList.count).contains(
|
||||||
|
self.tblServices.selectedRow)
|
||||||
|
}
|
||||||
|
guard row < Self.servicesList.count else { return "" }
|
||||||
|
if let column = column {
|
||||||
|
let colName = column.identifier.rawValue
|
||||||
|
switch colName {
|
||||||
|
case "colTitle": return Self.servicesList[row].key
|
||||||
|
case "colValue": return Self.servicesList[row].definedValue // TODO: 回頭這裡可能需要自訂。
|
||||||
|
default: return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Self.servicesList[row]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Pasteboard Operations.
|
||||||
|
|
||||||
|
public func tableView(
|
||||||
|
_: NSTableView, pasteboardWriterForRow row: Int
|
||||||
|
) -> NSPasteboardWriting? {
|
||||||
|
let pasteboard = NSPasteboardItem()
|
||||||
|
pasteboard.setString(row.description, forType: .string)
|
||||||
|
return pasteboard
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tableView(
|
||||||
|
_: NSTableView,
|
||||||
|
validateDrop _: NSDraggingInfo,
|
||||||
|
proposedRow _: Int,
|
||||||
|
proposedDropOperation _: NSTableView.DropOperation
|
||||||
|
) -> NSDragOperation {
|
||||||
|
.move
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tableView(
|
||||||
|
_ tableView: NSTableView,
|
||||||
|
acceptDrop info: NSDraggingInfo,
|
||||||
|
row: Int,
|
||||||
|
dropOperation _: NSTableView.DropOperation
|
||||||
|
) -> Bool {
|
||||||
|
var oldIndexes = [Int]()
|
||||||
|
info.enumerateDraggingItems(
|
||||||
|
options: [],
|
||||||
|
for: tableView,
|
||||||
|
classes: [NSPasteboardItem.self],
|
||||||
|
searchOptions: [:]
|
||||||
|
) { dragItem, _, _ in
|
||||||
|
guard let pasteboardItem = dragItem.item as? NSPasteboardItem else { return }
|
||||||
|
guard let index = Int(pasteboardItem.string(forType: .string) ?? "NULL"), index >= 0 else { return }
|
||||||
|
oldIndexes.append(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldIndexOffset = 0
|
||||||
|
var newIndexOffset = 0
|
||||||
|
|
||||||
|
tableView.beginUpdates()
|
||||||
|
for oldIndex in oldIndexes {
|
||||||
|
if oldIndex < row {
|
||||||
|
let contentToMove = Self.servicesList[oldIndex + oldIndexOffset]
|
||||||
|
Self.servicesList.remove(at: oldIndex + oldIndexOffset)
|
||||||
|
Self.servicesList.insert(contentToMove, at: row - 1)
|
||||||
|
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
|
||||||
|
oldIndexOffset -= 1
|
||||||
|
} else {
|
||||||
|
let contentToMove = Self.servicesList[oldIndex]
|
||||||
|
Self.servicesList.remove(at: oldIndex)
|
||||||
|
Self.servicesList.insert(contentToMove, at: row + newIndexOffset)
|
||||||
|
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
|
||||||
|
newIndexOffset += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableView.endUpdates()
|
||||||
|
reassureButtonAvailability()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preview.
|
||||||
|
|
||||||
|
@available(macOS 14.0, *)
|
||||||
|
#Preview(traits: .fixedLayout(width: 770, height: 335)) {
|
||||||
|
VwrServiceMenuEditor()
|
||||||
|
}
|
|
@ -125,6 +125,8 @@ extension SessionCtl: CtlCandidateDelegate {
|
||||||
return shortened ? theEmoji : "\(theEmoji) " + NSLocalizedString("Quick Candidates", comment: "")
|
return shortened ? theEmoji : "\(theEmoji) " + NSLocalizedString("Quick Candidates", comment: "")
|
||||||
} else if PrefMgr.shared.cassetteEnabled {
|
} else if PrefMgr.shared.cassetteEnabled {
|
||||||
return shortened ? "📼" : "📼 " + NSLocalizedString("CIN Cassette Mode", comment: "")
|
return shortened ? "📼" : "📼 " + NSLocalizedString("CIN Cassette Mode", comment: "")
|
||||||
|
} else if state.type == .ofSymbolTable, state.node.containsCandidateServices {
|
||||||
|
return shortened ? "🌎" : "🌎 " + NSLocalizedString("Service Menu", comment: "")
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -201,6 +203,22 @@ extension SessionCtl: CtlCandidateDelegate {
|
||||||
let node = state.node.members[index]
|
let node = state.node.members[index]
|
||||||
if !node.members.isEmpty {
|
if !node.members.isEmpty {
|
||||||
switchState(IMEState.ofSymbolTable(node: node))
|
switchState(IMEState.ofSymbolTable(node: node))
|
||||||
|
} else if let serviceNode = node.asServiceMenuNode {
|
||||||
|
switch serviceNode.service.value {
|
||||||
|
case let .url(theURL):
|
||||||
|
// 雖然 Safari 理論上是啟動速度最快的,但這裡還是尊重一下使用者各自電腦內的偏好設定好了。
|
||||||
|
NSWorkspace.shared.open(theURL)
|
||||||
|
case .selector:
|
||||||
|
if let response = serviceNode.service.responseFromSelector {
|
||||||
|
NSPasteboard.general.declareTypes([.string], owner: nil)
|
||||||
|
NSPasteboard.general.setString(response, forType: .string)
|
||||||
|
Notifier.notify(message: "i18n:candidateServiceMenu.selectorResponse.succeeded".localized)
|
||||||
|
} else {
|
||||||
|
callError("4DFDC487: Candidate Text Service Selector Responsiveness Failure.")
|
||||||
|
Notifier.notify(message: "i18n:candidateServiceMenu.selectorResponse.failed".localized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switchState(IMEState.ofAbortion())
|
||||||
} else {
|
} else {
|
||||||
switchState(IMEState.ofCommitting(textToCommit: node.name))
|
switchState(IMEState.ofCommitting(textToCommit: node.name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,13 +79,12 @@ public extension SessionCtl {
|
||||||
func showCandidates() {
|
func showCandidates() {
|
||||||
guard client() != nil else { return }
|
guard client() != nil else { return }
|
||||||
updateVerticalTypingStatus()
|
updateVerticalTypingStatus()
|
||||||
isVerticalCandidateWindow = (isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList)
|
let isServiceMenu = state.type == .ofSymbolTable && state.node.containsCandidateServices
|
||||||
|
isVerticalCandidateWindow = isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList
|
||||||
|
isVerticalCandidateWindow = isVerticalCandidateWindow || isServiceMenu
|
||||||
|
|
||||||
/// 無論是田所選字窗還是 IMK 選字窗,在這裡都有必要重新初期化。
|
/// 無論是田所選字窗還是 IMK 選字窗,在這裡都有必要重新初期化。
|
||||||
let candidateLayout: NSUserInterfaceLayoutOrientation =
|
let candidateLayout: NSUserInterfaceLayoutOrientation = (isVerticalCandidateWindow ? .vertical : .horizontal)
|
||||||
((isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList)
|
|
||||||
? .vertical
|
|
||||||
: .horizontal)
|
|
||||||
|
|
||||||
let isInputtingWithCandidates = state.type == .ofInputting && state.isCandidateContainer
|
let isInputtingWithCandidates = state.type == .ofInputting && state.isCandidateContainer
|
||||||
/// 先取消既有的選字窗的內容顯示。否則可能會重複生成選字窗的 NSWindow()。
|
/// 先取消既有的選字窗的內容顯示。否則可能會重複生成選字窗的 NSWindow()。
|
||||||
|
@ -93,6 +92,8 @@ public extension SessionCtl {
|
||||||
candidateUI = CtlCandidateTDK(candidateLayout)
|
candidateUI = CtlCandidateTDK(candidateLayout)
|
||||||
var singleLine = isVerticalTyping || PrefMgr.shared.candidateWindowShowOnlyOneLine
|
var singleLine = isVerticalTyping || PrefMgr.shared.candidateWindowShowOnlyOneLine
|
||||||
singleLine = singleLine || isInputtingWithCandidates
|
singleLine = singleLine || isInputtingWithCandidates
|
||||||
|
singleLine = singleLine || isServiceMenu
|
||||||
|
|
||||||
(candidateUI as? CtlCandidateTDK)?.maxLinesPerPage = singleLine ? 1 : 4
|
(candidateUI as? CtlCandidateTDK)?.maxLinesPerPage = singleLine ? 1 : 4
|
||||||
|
|
||||||
candidateUI?.candidateFont = Self.candidateFont(
|
candidateUI?.candidateFont = Self.candidateFont(
|
||||||
|
|
|
@ -129,6 +129,9 @@ extension SessionCtl {
|
||||||
NSMenu.Item(verbatim: "Client Manager".localized.withEllipsis)?
|
NSMenu.Item(verbatim: "Client Manager".localized.withEllipsis)?
|
||||||
.act(#selector(showClientListMgr(_:)))
|
.act(#selector(showClientListMgr(_:)))
|
||||||
.nulled(silentMode)
|
.nulled(silentMode)
|
||||||
|
NSMenu.Item(verbatim: "Service Menu Editor".localized.withEllipsis)?
|
||||||
|
.act(#selector(showServiceMenuEditor(_:)))
|
||||||
|
.alternated().nulled(silentMode)
|
||||||
NSMenu.Item("Check for Updates…")?
|
NSMenu.Item("Check for Updates…")?
|
||||||
.act(#selector(checkForUpdate(_:)))
|
.act(#selector(checkForUpdate(_:)))
|
||||||
.nulled(silentMode)
|
.nulled(silentMode)
|
||||||
|
@ -184,6 +187,11 @@ public extension SessionCtl {
|
||||||
NSApp.popup()
|
NSApp.popup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc func showServiceMenuEditor(_: Any? = nil) {
|
||||||
|
CtlServiceMenuEditor.show()
|
||||||
|
NSApp.popup()
|
||||||
|
}
|
||||||
|
|
||||||
@objc func toggleCassetteMode(_: Any? = nil) {
|
@objc func toggleCassetteMode(_: Any? = nil) {
|
||||||
resetInputHandler(forceComposerCleanup: true)
|
resetInputHandler(forceComposerCleanup: true)
|
||||||
if !PrefMgr.shared.cassetteEnabled, !LMMgr.checkCassettePathValidity(PrefMgr.shared.cassettePath) {
|
if !PrefMgr.shared.cassetteEnabled, !LMMgr.checkCassettePathValidity(PrefMgr.shared.cassettePath) {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"About vChewing…" = "About vChewing…";
|
"About vChewing…" = "About vChewing…";
|
||||||
"Accept leading intonations in rare cases" = "Accept leading intonations in rare cases";
|
"Accept leading intonations in rare cases" = "Accept leading intonations in rare cases";
|
||||||
"Add Client" = "Add Client";
|
"Add Client" = "Add Client";
|
||||||
|
"Add Service" = "Add Service";
|
||||||
"Adjust candidate window location according to current node length" = "Adjust candidate window location according to current node length";
|
"Adjust candidate window location according to current node length" = "Adjust candidate window location according to current node length";
|
||||||
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file.";
|
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file.";
|
||||||
"Allow backspace-editing miscomposed readings" = "Allow backspace-editing miscomposed readings";
|
"Allow backspace-editing miscomposed readings" = "Allow backspace-editing miscomposed readings";
|
||||||
|
@ -125,6 +126,7 @@
|
||||||
"Completely disable using Shift key to toggle alphanumerical mode" = "Completely disable using Shift key to toggle alphanumerical mode";
|
"Completely disable using Shift key to toggle alphanumerical mode" = "Completely disable using Shift key to toggle alphanumerical mode";
|
||||||
"Consolidate the context on confirming candidate selection" = "Consolidate the context on confirming candidate selection";
|
"Consolidate the context on confirming candidate selection" = "Consolidate the context on confirming candidate selection";
|
||||||
"Consolidate" = "Consolidate";
|
"Consolidate" = "Consolidate";
|
||||||
|
"Copy All to Clipboard" = "Copy All to Clipboard";
|
||||||
"Core Dict loading complete." = "Core Dict loading complete.";
|
"Core Dict loading complete." = "Core Dict loading complete.";
|
||||||
"Currency Numeral Output" = "Currency Numeral Output";
|
"Currency Numeral Output" = "Currency Numeral Output";
|
||||||
"Cursor Selection:" = "Cursor Selection:";
|
"Cursor Selection:" = "Cursor Selection:";
|
||||||
|
@ -183,6 +185,7 @@
|
||||||
"Harden vertical punctuations during vertical typing (not recommended)" = "Harden vertical punctuations during vertical typing (not recommended)";
|
"Harden vertical punctuations during vertical typing (not recommended)" = "Harden vertical punctuations during vertical typing (not recommended)";
|
||||||
"Hold ⇧ to choose associates." = "Hold ⇧ to choose associates.";
|
"Hold ⇧ to choose associates." = "Hold ⇧ to choose associates.";
|
||||||
"Horizontal" = "Horizontal";
|
"Horizontal" = "Horizontal";
|
||||||
|
"How to Fill" = "How to Fill";
|
||||||
"Hsu" = "Hsu";
|
"Hsu" = "Hsu";
|
||||||
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
|
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
|
||||||
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "About vChewing for macOS";
|
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "About vChewing for macOS";
|
||||||
|
@ -195,6 +198,14 @@
|
||||||
"i18n:aboutWindow.OK_BUTTON" = "I Accept";
|
"i18n:aboutWindow.OK_BUTTON" = "I Accept";
|
||||||
"i18n:aboutWindow.WEBSITE_BUTTON" = "Website";
|
"i18n:aboutWindow.WEBSITE_BUTTON" = "Website";
|
||||||
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "Candidates cannot have those keys who are assigned for other purposes.";
|
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "Candidates cannot have those keys who are assigned for other purposes.";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.failed" = "Failed\nEither ObjC Selector mismatch or no result available.";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.succeeded" = "Succeeded\nResults are available in Clipboard.";
|
||||||
|
"i18n:CandidateServiceMenuEditor.description" = "Candidate Service Menu can be called in Candidate Window by using “(Shift+)SymbolMenuKey”. The currently highlighted candidate will be used as the parameter for calling the Service Menu. Depending on what listed in the current window (Service Menu Editor), some services are for opening a designated web browser page to query the parameter, and some are for local-generating some computed results to your clipboard.\n\nP.S.: If no service is registered in the current window, then the above hotkey will behave as alternative page-flipping shortcuts.";
|
||||||
|
"i18n:CandidateServiceMenuEditor.formatGuide" = "Here are the formatting rules of the Service Metadata:\n\n1. One definition per line. Use “Tab” as delimiter to divide the two cells. The parameter “%s” written in the Menu Item Title will be replaced using the real parameter data when you are using the service. If the parameter consists of only one character, then its codepoint will be attached to the end of the Menu Item Title.\n\n2. The Defined Value begins with “@SEL:” or “@WEB:” or “@URL:”. Here are their differences:\n\n- “@SEL:” means that the remaining string should be the name of the specified Objective-C Selector. It must be ended with an ASCII colon. This method is to call some internal features in vChewing to retrieve locally-generated query results.\n\n- “@WEB:” and “@URL:” are exactly the same, indicating that the remaining string should be an URL for the web page to query the parameter. The parameter “%s” written in the URL will be replaced using the real parameter data when you are using the service.";
|
||||||
|
"i18n:CandidateServiceMenuEditor.howToGetGuide" = "You may hover your mouse pointer onto the editing area to see the pop-up data-filling instructions.";
|
||||||
|
"i18n:CandidateServiceMenuEditor.prompt" = "Please input the service metadata you want to register.";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.MenuTitle" = "Menu Item Title";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.Value" = "Defined Value";
|
||||||
"i18n:KimoDataImportError.connectionFailure.errMsg" = "Directly Import is not available due to an NSConnection failure.\n\n- Please enable Yahoo! KeyKey Input Method and run it prior to performing the current action. vChewing now have just triggered Yahoo! KeyKey Input Method to run, so you can retry the import immediately.\n\n- If this copy of vChewing is compiled by yourself, please double-check the Sandbox Entitlements you have modified.\n\n- If this mac is not an Intel Mac, then Rosetta 2 is required to run Yahoo! KeyKey Input Method.\n\n- If all of the above reasons are not met in this case, then the __objc_empty_cache API might be unavailable in the current system. This API is crucial in order to let Yahoo! KeyKey Input Method run. Please double check the Console.app in your system to see whether there are any crash reports related to Yahoo! KeyKey Input Method.";
|
"i18n:KimoDataImportError.connectionFailure.errMsg" = "Directly Import is not available due to an NSConnection failure.\n\n- Please enable Yahoo! KeyKey Input Method and run it prior to performing the current action. vChewing now have just triggered Yahoo! KeyKey Input Method to run, so you can retry the import immediately.\n\n- If this copy of vChewing is compiled by yourself, please double-check the Sandbox Entitlements you have modified.\n\n- If this mac is not an Intel Mac, then Rosetta 2 is required to run Yahoo! KeyKey Input Method.\n\n- If all of the above reasons are not met in this case, then the __objc_empty_cache API might be unavailable in the current system. This API is crucial in order to let Yahoo! KeyKey Input Method run. Please double check the Console.app in your system to see whether there are any crash reports related to Yahoo! KeyKey Input Method.";
|
||||||
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "Failed in writing new user phrases data.";
|
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "Failed in writing new user phrases data.";
|
||||||
"i18n:kimoImportButton.DragFileToHere" = "DRAG FILE TO HERE";
|
"i18n:kimoImportButton.DragFileToHere" = "DRAG FILE TO HERE";
|
||||||
|
@ -319,12 +330,14 @@
|
||||||
"Reload" = "Reload";
|
"Reload" = "Reload";
|
||||||
"Remove Selected" = "Remove Selected";
|
"Remove Selected" = "Remove Selected";
|
||||||
"Replace to" = "Replace to";
|
"Replace to" = "Replace to";
|
||||||
|
"Reset Default" = "Reset Default";
|
||||||
"Reverse Lookup (Phonabets)" = "Reverse Lookup (Phonabets)";
|
"Reverse Lookup (Phonabets)" = "Reverse Lookup (Phonabets)";
|
||||||
"Save" = "Save";
|
"Save" = "Save";
|
||||||
"Secondary Pinyin with Numeral Intonation" = "Secondary Pinyin with Numeral Intonation";
|
"Secondary Pinyin with Numeral Intonation" = "Secondary Pinyin with Numeral Intonation";
|
||||||
"Security-harden the composition buffer for all clients" = "Security-harden the composition buffer for all clients";
|
"Security-harden the composition buffer for all clients" = "Security-harden the composition buffer for all clients";
|
||||||
"Seigyou" = "Seigyou (JinYei)";
|
"Seigyou" = "Seigyou (JinYei)";
|
||||||
"Selection Keys:" = "Selection Keys:";
|
"Selection Keys:" = "Selection Keys:";
|
||||||
|
"Service Menu Editor" = "Service Menu Editor";
|
||||||
"Share alphanumerical mode status across all clients" = "Share alphanumerical mode status across all clients";
|
"Share alphanumerical mode status across all clients" = "Share alphanumerical mode status across all clients";
|
||||||
"Shift+BackSpace:" = "Shift+BackSpace:";
|
"Shift+BackSpace:" = "Shift+BackSpace:";
|
||||||
"Shift+Letter:" = "Shift+Letter:";
|
"Shift+Letter:" = "Shift+Letter:";
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"About vChewing…" = "威注音について…";
|
"About vChewing…" = "威注音について…";
|
||||||
"Accept leading intonations in rare cases" = "まれな場合には、音調記号の優先入力を許容する";
|
"Accept leading intonations in rare cases" = "まれな場合には、音調記号の優先入力を許容する";
|
||||||
"Add Client" = "入れる";
|
"Add Client" = "入れる";
|
||||||
|
"Add Service" = "サービスを追加";
|
||||||
"Adjust candidate window location according to current node length" = "カーソル所在位置の単語の長さによって候補陳列ウィンドウの位置を調整";
|
"Adjust candidate window location according to current node length" = "カーソル所在位置の単語の長さによって候補陳列ウィンドウの位置を調整";
|
||||||
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "これをチェックしないと、全ての筆画は ASCII キーネームで入力緩衝列で表示してしまうことになる。CIN ファイルの「%keyname」というところで筆画の定義はできる。";
|
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "これをチェックしないと、全ての筆画は ASCII キーネームで入力緩衝列で表示してしまうことになる。CIN ファイルの「%keyname」というところで筆画の定義はできる。";
|
||||||
"Allow backspace-editing miscomposed readings" = "効かぬ音読みを BackSpace で再編集";
|
"Allow backspace-editing miscomposed readings" = "効かぬ音読みを BackSpace で再編集";
|
||||||
|
@ -125,6 +126,7 @@
|
||||||
"Completely disable using Shift key to toggle alphanumerical mode" = "Shift キーの英数入力モードの切り替え機能を徹底的に禁ず";
|
"Completely disable using Shift key to toggle alphanumerical mode" = "Shift キーの英数入力モードの切り替え機能を徹底的に禁ず";
|
||||||
"Consolidate the context on confirming candidate selection" = "候補陳列ウィンドウで候補を選ぶ時に文脈を強固する";
|
"Consolidate the context on confirming candidate selection" = "候補陳列ウィンドウで候補を選ぶ時に文脈を強固する";
|
||||||
"Consolidate" = "整理";
|
"Consolidate" = "整理";
|
||||||
|
"Copy All to Clipboard" = "全てをクリップボードにコピー";
|
||||||
"Core Dict loading complete." = "核心辞書読込完了";
|
"Core Dict loading complete." = "核心辞書読込完了";
|
||||||
"Currency Numeral Output" = "数字大字変換";
|
"Currency Numeral Output" = "数字大字変換";
|
||||||
"Cursor Selection:" = "カーソル候補呼出:";
|
"Cursor Selection:" = "カーソル候補呼出:";
|
||||||
|
@ -183,6 +185,7 @@
|
||||||
"Harden vertical punctuations during vertical typing (not recommended)" = "縦書きの時に、引用符・括弧などを強制的に縦書き文字と変換する(不推奨)";
|
"Harden vertical punctuations during vertical typing (not recommended)" = "縦書きの時に、引用符・括弧などを強制的に縦書き文字と変換する(不推奨)";
|
||||||
"Hold ⇧ to choose associates." = "⇧を押しながら連想候補を選択。";
|
"Hold ⇧ to choose associates." = "⇧を押しながら連想候補を選択。";
|
||||||
"Horizontal" = "横型陳列";
|
"Horizontal" = "横型陳列";
|
||||||
|
"How to Fill" = "記入方法";
|
||||||
"Hsu" = "許氏国音自然配列";
|
"Hsu" = "許氏国音自然配列";
|
||||||
"Hualuo Pinyin with Numeral Intonation" = "中華ローマ弁音 (ローマ字+数字音調)";
|
"Hualuo Pinyin with Numeral Intonation" = "中華ローマ弁音 (ローマ字+数字音調)";
|
||||||
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "macOS 版威注音入力アプリについて";
|
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "macOS 版威注音入力アプリについて";
|
||||||
|
@ -195,6 +198,14 @@
|
||||||
"i18n:aboutWindow.OK_BUTTON" = "うむ";
|
"i18n:aboutWindow.OK_BUTTON" = "うむ";
|
||||||
"i18n:aboutWindow.WEBSITE_BUTTON" = "公式HP";
|
"i18n:aboutWindow.WEBSITE_BUTTON" = "公式HP";
|
||||||
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "他の用途に指定したキーは言選りには使えません。";
|
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "他の用途に指定したキーは言選りには使えません。";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.failed" = "請求失敗\n一致なる Selector あるいは利用できる結果はございません。";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.succeeded" = "結果獲得完了\n取得した結果はクリップボードに書き込みました。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.description"="サービスメニューは候補陳列ウィンドウで「(Shift+)符号メニューキー」で呼び出せるメニューです。ハイライトされている候補はサービスメニューを呼び出すためのパラメータとして使用されます。現在のウィンドウ(サービスメニューエディター)に陳列中のメタデータによって、パラメーターをクエリするために指定済みのウェブページを開くサービスもあれば、クリップボードに(このパソコンでの)計算結果を書き出すサービスもございます。\n\n追記: 現在のウィンドウにサービスが登録されていない場合、上記のショートカットは代わりに「ページをめくるショートカット」として動作します。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.formatGuide" = "サービスメタデータのフォーマット規則です。\n\nイ)1 行に 1 定義。2 つのセルを区切るには、区切り文字として「Tab」をご使用ください。メニュー項目タイトルに含むパラメータ「%s」は、サービス利用時に実際のパラメータデータと置き換わります。パラメータが 1 文字の場合は、メニュー項目名の末尾に UTF コードポイントが付きます。\n\nロ)定義値の冒頭部分は「@SEL:」か「@WEB:」か「@URL:」であり、それぞれの意味:\n\n- 「@SEL:」がつく場合:残りの文字列はご指定の Objective-C Selector の名前とします。Selector の名前の最後文字は必ず「ASCII コロン」です。これで弊アプリのいくつかの内部機能を用いて(このパソコンでの)計算結果をを取得することができます。\n\n- 「@WEB:」・「@URL:」がつく場合:残りの文字列は「パラメータをクエリするための」Web ページの URL です。その URL に含むパラメータ「%s」は、サービス利用時に実際のパラメータデータと置き換わります。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.howToGetGuide" = "編集エリアにマウスポインターをホバーすると、ポップアップで「データ入力の説明」が表示されます。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.prompt" = "登録したいサービスのメタデータを入力してください。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.MenuTitle" = "メニュー項目タイトル";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.Value" = "定義値";
|
||||||
"i18n:KimoDataImportError.connectionFailure.errMsg" = "「直接読み込む」作動失敗:両アプリの NSConnection 通信はできませんでした。\n\n- 「直接読込」を続行する前に、まずは Yahoo! KeyKey そのアプリを実行すること。弊アプリは Yahoo! KeyKey をすでに1度呼び覚ませてみたため、すぐにもう一度「直接読込」するのも可能です。\n\n- 今の実行中の弊アプリはご自分で Xcode で組み立てた場合、Xcode プロジェクトの Sandbox Entitlements の配置の正しさをご確認ください。\n\n- 今のパソコンは Intel Mac ではない場合、必ず Rosetta 2 をご実装ください。Yahoo! KeyKey の実行には Rosetta 2 は必要条件です。\n\n- 上記のすべての状況を排除したら、多分「__objc_empty_cache」という肝心なる API は今のこのシステムでもう利用できないと推測できます。この API がない限り、Yahoo! KeyKey の実行は不可能です。今のこのシステムの「Console.app」で Yahoo! KeyKey の故障報告の有無をご確認ください。";
|
"i18n:KimoDataImportError.connectionFailure.errMsg" = "「直接読み込む」作動失敗:両アプリの NSConnection 通信はできませんでした。\n\n- 「直接読込」を続行する前に、まずは Yahoo! KeyKey そのアプリを実行すること。弊アプリは Yahoo! KeyKey をすでに1度呼び覚ませてみたため、すぐにもう一度「直接読込」するのも可能です。\n\n- 今の実行中の弊アプリはご自分で Xcode で組み立てた場合、Xcode プロジェクトの Sandbox Entitlements の配置の正しさをご確認ください。\n\n- 今のパソコンは Intel Mac ではない場合、必ず Rosetta 2 をご実装ください。Yahoo! KeyKey の実行には Rosetta 2 は必要条件です。\n\n- 上記のすべての状況を排除したら、多分「__objc_empty_cache」という肝心なる API は今のこのシステムでもう利用できないと推測できます。この API がない限り、Yahoo! KeyKey の実行は不可能です。今のこのシステムの「Console.app」で Yahoo! KeyKey の故障報告の有無をご確認ください。";
|
||||||
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "新しい資料はユーザー辞書データファイルに書き込むのはできませんでした。";
|
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "新しい資料はユーザー辞書データファイルに書き込むのはできませんでした。";
|
||||||
"i18n:kimoImportButton.DragFileToHere" = "ここにドラッグして";
|
"i18n:kimoImportButton.DragFileToHere" = "ここにドラッグして";
|
||||||
|
@ -319,12 +330,14 @@
|
||||||
"Reload" = "再読込";
|
"Reload" = "再読込";
|
||||||
"Remove Selected" = "外す";
|
"Remove Selected" = "外す";
|
||||||
"Replace to" = "単語 →";
|
"Replace to" = "単語 →";
|
||||||
|
"Reset Default" = "全てをリセット";
|
||||||
"Reverse Lookup (Phonabets)" = "注音音読逆引参照";
|
"Reverse Lookup (Phonabets)" = "注音音読逆引参照";
|
||||||
"Save" = "セーブ";
|
"Save" = "セーブ";
|
||||||
"Secondary Pinyin with Numeral Intonation" = "国音二式 (ローマ字+数字音調)";
|
"Secondary Pinyin with Numeral Intonation" = "国音二式 (ローマ字+数字音調)";
|
||||||
"Security-harden the composition buffer for all clients" = "全ての客体アプリに対して、入力緩衝列にセキュリティ強化対策を起用";
|
"Security-harden the composition buffer for all clients" = "全ての客体アプリに対して、入力緩衝列にセキュリティ強化対策を起用";
|
||||||
"Seigyou" = "精業配列";
|
"Seigyou" = "精業配列";
|
||||||
"Selection Keys:" = "言選り用キー:";
|
"Selection Keys:" = "言選り用キー:";
|
||||||
|
"Service Menu Editor" = "サービスメニューエディター";
|
||||||
"Share alphanumerical mode status across all clients" = "全ての客体アプリに英数入力モードの状態を共有";
|
"Share alphanumerical mode status across all clients" = "全ての客体アプリに英数入力モードの状態を共有";
|
||||||
"Shift+BackSpace:" = "Shift+BackSpace:";
|
"Shift+BackSpace:" = "Shift+BackSpace:";
|
||||||
"Shift+Letter:" = "Shift+文字キー:";
|
"Shift+Letter:" = "Shift+文字キー:";
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"About vChewing…" = "关于威注音…";
|
"About vChewing…" = "关于威注音…";
|
||||||
"Accept leading intonations in rare cases" = "在个别情况下,允许声调前置键入";
|
"Accept leading intonations in rare cases" = "在个别情况下,允许声调前置键入";
|
||||||
"Add Client" = "登记新客体";
|
"Add Client" = "登记新客体";
|
||||||
|
"Add Service" = "新增服务";
|
||||||
"Adjust candidate window location according to current node length" = "根据当前位置的字词长度,自动调整选字窗的位置";
|
"Adjust candidate window location according to current node length" = "根据当前位置的字词长度,自动调整选字窗的位置";
|
||||||
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "不启用该选项的话,在组字区内的字根将会以原始键盘按键名称来显示。所有关于字根的定义,均请洽 CIN 磁带档案内的「%keyname」章节。";
|
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "不启用该选项的话,在组字区内的字根将会以原始键盘按键名称来显示。所有关于字根的定义,均请洽 CIN 磁带档案内的「%keyname」章节。";
|
||||||
"Allow backspace-editing miscomposed readings" = "允许对无效的读音使用 BackSpace 编辑";
|
"Allow backspace-editing miscomposed readings" = "允许对无效的读音使用 BackSpace 编辑";
|
||||||
|
@ -125,6 +126,7 @@
|
||||||
"Completely disable using Shift key to toggle alphanumerical mode" = "彻底禁止使用 Shift 键切换英数模式";
|
"Completely disable using Shift key to toggle alphanumerical mode" = "彻底禁止使用 Shift 键切换英数模式";
|
||||||
"Consolidate the context on confirming candidate selection" = "在使用选字窗选字时,自动巩固上下文";
|
"Consolidate the context on confirming candidate selection" = "在使用选字窗选字时,自动巩固上下文";
|
||||||
"Consolidate" = "整理";
|
"Consolidate" = "整理";
|
||||||
|
"Copy All to Clipboard" = "全部拷贝到剪贴簿";
|
||||||
"Core Dict loading complete." = "核心辞典载入完毕";
|
"Core Dict loading complete." = "核心辞典载入完毕";
|
||||||
"Currency Numeral Output" = "大写汉字数字输出";
|
"Currency Numeral Output" = "大写汉字数字输出";
|
||||||
"Cursor Selection:" = "选字游标:";
|
"Cursor Selection:" = "选字游标:";
|
||||||
|
@ -183,6 +185,7 @@
|
||||||
"Harden vertical punctuations during vertical typing (not recommended)" = "在纵排书写时,强制转换标点为纵排形式(不推荐)";
|
"Harden vertical punctuations during vertical typing (not recommended)" = "在纵排书写时,强制转换标点为纵排形式(不推荐)";
|
||||||
"Hold ⇧ to choose associates." = "摁住⇧以选取关联词语。";
|
"Hold ⇧ to choose associates." = "摁住⇧以选取关联词语。";
|
||||||
"Horizontal" = "横向布局";
|
"Horizontal" = "横向布局";
|
||||||
|
"How to Fill" = "填写指引";
|
||||||
"Hsu" = "许氏国音自然排列";
|
"Hsu" = "许氏国音自然排列";
|
||||||
"Hualuo Pinyin with Numeral Intonation" = "华罗拼音+数字标调";
|
"Hualuo Pinyin with Numeral Intonation" = "华罗拼音+数字标调";
|
||||||
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "关于 macOS 版「威注音输入法」";
|
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "关于 macOS 版「威注音输入法」";
|
||||||
|
@ -195,6 +198,14 @@
|
||||||
"i18n:aboutWindow.OK_BUTTON" = "确定";
|
"i18n:aboutWindow.OK_BUTTON" = "确定";
|
||||||
"i18n:aboutWindow.WEBSITE_BUTTON" = "网站";
|
"i18n:aboutWindow.WEBSITE_BUTTON" = "网站";
|
||||||
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "无法将已挪作他用的按键设为选字键。";
|
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "无法将已挪作他用的按键设为选字键。";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.failed" = "请求失败\nSelector 指令匹配失败、或无结果可用。";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.succeeded" = "成功取得结果\n已将结果写入剪贴簿。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.description" = "服务选单可以在选字窗内借由「(Shift+)符号选单键」呼出。在您呼出该选单的那一刻,原先的选字窗内的高亮选中的候选字词将成为该服务选单内各个功能的处理参数。根据当前视窗(服务选单管理器)内所陈列的服务的不同,有些服务是会叫出浏览器前往指定网页检索指定内容,而有些服务则可能会将本地计算的某些结果自动拷贝到您的剪贴簿内。\n\n注:如果当前视窗内没有任何可用的服务选单资料的话,上述热键在选字窗内的对应的行为会是辅助翻页。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.formatGuide" = "填写规则大致如下:\n\n1. 每行一笔定义,选单条目名称与定义资料值以 Tab 字元分割。选单名称当中的「%s」会在使用服务时被置换成传入的参数。如果参数只有一个字元的话,则程式会自动在选单名称结尾用括弧追加显示其统一码码位。\n\n2. 定义资料值的开头是「@SEL:」或「@WEB:」或「@URL:」,其中:\n\n- 「@SEL:」对应 Objective-C Selector 名称,可以呼叫威注音输入法内部预先定义的某些资料生成功能。直接在此之后紧接着填写 Selector 名称即可(须以西文半形冒号结尾)。\n\n- 「@WEB:」与「@URL:」等价,用来紧接着填写网址。网址当中的「%s」会在使用服务时被置换成传入的参数。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.howToGetGuide" = "可将滑鼠悬停于编辑区内、以检视资料填写指引。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.prompt" = "请键入您要登记的服务资料。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.MenuTitle" = "选单条目名称";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.Value" = "定义资料值";
|
||||||
"i18n:KimoDataImportError.connectionFailure.errMsg" = "「直接汇入」功能失败:无法成功建立 NSConnection 跨执行绪通讯。\n\n- 在执行该步骤之前,请确保奇摩输入法有在运行。威注音输入法已经在此刻发起了一次对奇摩输入法的运行呼叫请求,于是您可以立刻再次重试。\n\n- 如果您当前运行的威注音输入法的程式包是您自己建置的话,请检查专案内的 Sandbox 权能组态设定档案(Entitlements)、看看是否发生了与此有关的内容变更。\n\n- 如果这台 Mac 并未使用 Intel CPU 的话,请先安装 Rosetta 2,否则奇摩输入法将无法运作。\n\n- 如果以上状况都被排除了的话,那么 __objc_empty_cache 这个 API 可能在当前版本的作业系统内被移除了。这个 API 对奇摩输入法而言至关重要。请检查您当前的作业系统内建的「系统监视程式 Console.app」,确认一下是否有与奇摩输入法有关的程式崩溃报告。";
|
"i18n:KimoDataImportError.connectionFailure.errMsg" = "「直接汇入」功能失败:无法成功建立 NSConnection 跨执行绪通讯。\n\n- 在执行该步骤之前,请确保奇摩输入法有在运行。威注音输入法已经在此刻发起了一次对奇摩输入法的运行呼叫请求,于是您可以立刻再次重试。\n\n- 如果您当前运行的威注音输入法的程式包是您自己建置的话,请检查专案内的 Sandbox 权能组态设定档案(Entitlements)、看看是否发生了与此有关的内容变更。\n\n- 如果这台 Mac 并未使用 Intel CPU 的话,请先安装 Rosetta 2,否则奇摩输入法将无法运作。\n\n- 如果以上状况都被排除了的话,那么 __objc_empty_cache 这个 API 可能在当前版本的作业系统内被移除了。这个 API 对奇摩输入法而言至关重要。请检查您当前的作业系统内建的「系统监视程式 Console.app」,确认一下是否有与奇摩输入法有关的程式崩溃报告。";
|
||||||
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "没能将新的资料成功写入到使用者自订语汇辞典当中。";
|
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "没能将新的资料成功写入到使用者自订语汇辞典当中。";
|
||||||
"i18n:kimoImportButton.DragFileToHere" = "请将档案拽到这边";
|
"i18n:kimoImportButton.DragFileToHere" = "请将档案拽到这边";
|
||||||
|
@ -319,12 +330,14 @@
|
||||||
"Reload" = "重新载入";
|
"Reload" = "重新载入";
|
||||||
"Remove Selected" = "移除所选条目";
|
"Remove Selected" = "移除所选条目";
|
||||||
"Replace to" = "置换 为";
|
"Replace to" = "置换 为";
|
||||||
|
"Reset Default" = "恢复原厂设定";
|
||||||
"Reverse Lookup (Phonabets)" = "注音反查";
|
"Reverse Lookup (Phonabets)" = "注音反查";
|
||||||
"Save" = "存档";
|
"Save" = "存档";
|
||||||
"Secondary Pinyin with Numeral Intonation" = "国音二式+数字标调";
|
"Secondary Pinyin with Numeral Intonation" = "国音二式+数字标调";
|
||||||
"Security-harden the composition buffer for all clients" = "针对所有客体软体启用强化型组字区安全防护";
|
"Security-harden the composition buffer for all clients" = "针对所有客体软体启用强化型组字区安全防护";
|
||||||
"Seigyou" = "精业排列";
|
"Seigyou" = "精业排列";
|
||||||
"Selection Keys:" = "选字键:";
|
"Selection Keys:" = "选字键:";
|
||||||
|
"Service Menu Editor" = "服务选单编辑器";
|
||||||
"Share alphanumerical mode status across all clients" = "对所有客体应用共用中英文输入切换状态";
|
"Share alphanumerical mode status across all clients" = "对所有客体应用共用中英文输入切换状态";
|
||||||
"Shift+BackSpace:" = "Shift+退格键:";
|
"Shift+BackSpace:" = "Shift+退格键:";
|
||||||
"Shift+Letter:" = "Shift+字母键:";
|
"Shift+Letter:" = "Shift+字母键:";
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"About vChewing…" = "關於威注音…";
|
"About vChewing…" = "關於威注音…";
|
||||||
"Accept leading intonations in rare cases" = "在個別情況下,允許聲調前置鍵入";
|
"Accept leading intonations in rare cases" = "在個別情況下,允許聲調前置鍵入";
|
||||||
"Add Client" = "登記新客體";
|
"Add Client" = "登記新客體";
|
||||||
|
"Add Service" = "新增服務";
|
||||||
"Adjust candidate window location according to current node length" = "根據當前位置的字詞長度,自動調整選字窗的位置";
|
"Adjust candidate window location according to current node length" = "根據當前位置的字詞長度,自動調整選字窗的位置";
|
||||||
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "不啟用該選項的話,在組字區內的字根將會以原始鍵盤按鍵名稱來顯示。所有關於字根的定義,均請洽 CIN 磁帶檔案內的「%keyname」章節。";
|
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file." = "不啟用該選項的話,在組字區內的字根將會以原始鍵盤按鍵名稱來顯示。所有關於字根的定義,均請洽 CIN 磁帶檔案內的「%keyname」章節。";
|
||||||
"Allow backspace-editing miscomposed readings" = "允許對無效的讀音使用 BackSpace 編輯";
|
"Allow backspace-editing miscomposed readings" = "允許對無效的讀音使用 BackSpace 編輯";
|
||||||
|
@ -125,6 +126,7 @@
|
||||||
"Completely disable using Shift key to toggle alphanumerical mode" = "徹底禁止使用 Shift 鍵切換英數模式";
|
"Completely disable using Shift key to toggle alphanumerical mode" = "徹底禁止使用 Shift 鍵切換英數模式";
|
||||||
"Consolidate the context on confirming candidate selection" = "在使用選字窗選字時,自動鞏固上下文";
|
"Consolidate the context on confirming candidate selection" = "在使用選字窗選字時,自動鞏固上下文";
|
||||||
"Consolidate" = "整理";
|
"Consolidate" = "整理";
|
||||||
|
"Copy All to Clipboard" = "全部拷貝到剪貼簿";
|
||||||
"Core Dict loading complete." = "核心辭典載入完畢";
|
"Core Dict loading complete." = "核心辭典載入完畢";
|
||||||
"Currency Numeral Output" = "大寫漢字數字輸出";
|
"Currency Numeral Output" = "大寫漢字數字輸出";
|
||||||
"Cursor Selection:" = "選字游標:";
|
"Cursor Selection:" = "選字游標:";
|
||||||
|
@ -183,6 +185,7 @@
|
||||||
"Harden vertical punctuations during vertical typing (not recommended)" = "在縱排書寫時,強制轉換標點為縱排形式(不推薦)";
|
"Harden vertical punctuations during vertical typing (not recommended)" = "在縱排書寫時,強制轉換標點為縱排形式(不推薦)";
|
||||||
"Hold ⇧ to choose associates." = "摁住⇧以選取關聯詞語。";
|
"Hold ⇧ to choose associates." = "摁住⇧以選取關聯詞語。";
|
||||||
"Horizontal" = "橫向佈局";
|
"Horizontal" = "橫向佈局";
|
||||||
|
"How to Fill" = "填寫指引";
|
||||||
"Hsu" = "許氏國音自然排列";
|
"Hsu" = "許氏國音自然排列";
|
||||||
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+數字標調";
|
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+數字標調";
|
||||||
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "關於 macOS 版「威注音輸入法」";
|
"i18n:aboutWindow.ABOUT_APP_TITLE_FULL" = "關於 macOS 版「威注音輸入法」";
|
||||||
|
@ -195,6 +198,14 @@
|
||||||
"i18n:aboutWindow.OK_BUTTON" = "確定";
|
"i18n:aboutWindow.OK_BUTTON" = "確定";
|
||||||
"i18n:aboutWindow.WEBSITE_BUTTON" = "網站";
|
"i18n:aboutWindow.WEBSITE_BUTTON" = "網站";
|
||||||
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "無法將已挪作他用的按鍵設為選字鍵。";
|
"i18n:CandidateKey.ValidationError.AssignedForOtherPurposes" = "無法將已挪作他用的按鍵設為選字鍵。";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.failed" = "請求失敗\nSelector 指令匹配失敗、或無結果可用。";
|
||||||
|
"i18n:candidateServiceMenu.selectorResponse.succeeded" = "成功取得結果\n已將結果寫入剪貼簿。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.description" = "服務選單可以在選字窗內藉由「(Shift+)符號選單鍵」呼出。在您呼出該選單的那一刻,原先的選字窗內的高亮選中的候選字詞將成為該服務選單內各個功能的處理參數。根據當前視窗(服務選單管理器)內所陳列的服務的不同,有些服務是會叫出瀏覽器前往指定網頁檢索指定內容,而有些服務則可能會將本地計算的某些結果自動拷貝到您的剪貼簿內。\n\n註:如果當前視窗內沒有任何可用的服務選單資料的話,上述熱鍵在選字窗內的對應的行為會是輔助翻頁。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.formatGuide" = "填寫規則大致如下:\n\n1. 每行一筆定義,選單條目名稱與定義資料值以 Tab 字元分割。選單名稱當中的「%s」會在使用服務時被置換成傳入的參數。如果參數只有一個字元的話,則程式會自動在選單名稱結尾用括弧追加顯示其統一碼碼位。\n\n2. 定義資料值的開頭是「@SEL:」或「@WEB:」或「@URL:」,其中:\n\n- 「@SEL:」對應 Objective-C Selector 名稱,可以呼叫威注音輸入法內部預先定義的某些資料生成功能。直接在此之後緊接著填寫 Selector 名稱即可(須以西文半形冒號結尾)。\n\n- 「@WEB:」與「@URL:」等價,用來緊接著填寫網址。網址當中的「%s」會在使用服務時被置換成傳入的參數。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.howToGetGuide" = "可將滑鼠懸停於編輯區內、以檢視資料填寫指引。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.prompt" = "請鍵入您要登記的服務資料。";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.MenuTitle" = "選單條目名稱";
|
||||||
|
"i18n:CandidateServiceMenuEditor.table.field.Value" = "定義資料值";
|
||||||
"i18n:KimoDataImportError.connectionFailure.errMsg" = "「直接匯入」功能失敗:無法成功建立 NSConnection 跨執行緒通訊。\n\n- 在執行該步驟之前,請確保奇摩輸入法有在運行。威注音輸入法已經在此刻發起了一次對奇摩輸入法的運行呼叫請求,於是您可以立刻再次重試。\n\n- 如果您當前運行的威注音輸入法的程式包是您自己建置的話,請檢查專案內的 Sandbox 權能組態設定檔案(Entitlements)、看看是否發生了與此有關的內容變更。\n\n- 如果這台 Mac 並未使用 Intel CPU 的話,請先安裝 Rosetta 2,否則奇摩輸入法將無法運作。\n\n- 如果以上狀況都被排除了的話,那麼 __objc_empty_cache 這個 API 可能在當前版本的作業系統內被移除了。這個 API 對奇摩輸入法而言至關重要。請檢查您當前的作業系統內建的「系統監視程式 Console.app」,確認一下是否有與奇摩輸入法有關的程式崩潰報告。";
|
"i18n:KimoDataImportError.connectionFailure.errMsg" = "「直接匯入」功能失敗:無法成功建立 NSConnection 跨執行緒通訊。\n\n- 在執行該步驟之前,請確保奇摩輸入法有在運行。威注音輸入法已經在此刻發起了一次對奇摩輸入法的運行呼叫請求,於是您可以立刻再次重試。\n\n- 如果您當前運行的威注音輸入法的程式包是您自己建置的話,請檢查專案內的 Sandbox 權能組態設定檔案(Entitlements)、看看是否發生了與此有關的內容變更。\n\n- 如果這台 Mac 並未使用 Intel CPU 的話,請先安裝 Rosetta 2,否則奇摩輸入法將無法運作。\n\n- 如果以上狀況都被排除了的話,那麼 __objc_empty_cache 這個 API 可能在當前版本的作業系統內被移除了。這個 API 對奇摩輸入法而言至關重要。請檢查您當前的作業系統內建的「系統監視程式 Console.app」,確認一下是否有與奇摩輸入法有關的程式崩潰報告。";
|
||||||
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "沒能將新的資料成功寫入到使用者自訂語彙辭典當中。";
|
"i18n:KimoDataImportError.fileHandlerFailure.errMsg" = "沒能將新的資料成功寫入到使用者自訂語彙辭典當中。";
|
||||||
"i18n:kimoImportButton.DragFileToHere" = "請將檔案拽到這邊";
|
"i18n:kimoImportButton.DragFileToHere" = "請將檔案拽到這邊";
|
||||||
|
@ -319,12 +330,14 @@
|
||||||
"Reload" = "重新載入";
|
"Reload" = "重新載入";
|
||||||
"Remove Selected" = "移除所選條目";
|
"Remove Selected" = "移除所選條目";
|
||||||
"Replace to" = "置換 為";
|
"Replace to" = "置換 為";
|
||||||
|
"Reset Default" = "恢復原廠設定";
|
||||||
"Reverse Lookup (Phonabets)" = "注音反查";
|
"Reverse Lookup (Phonabets)" = "注音反查";
|
||||||
"Save" = "存檔";
|
"Save" = "存檔";
|
||||||
"Secondary Pinyin with Numeral Intonation" = "國音二式+數字標調";
|
"Secondary Pinyin with Numeral Intonation" = "國音二式+數字標調";
|
||||||
"Security-harden the composition buffer for all clients" = "針對所有客體軟體啟用強化型組字區安全防護";
|
"Security-harden the composition buffer for all clients" = "針對所有客體軟體啟用強化型組字區安全防護";
|
||||||
"Seigyou" = "精業排列";
|
"Seigyou" = "精業排列";
|
||||||
"Selection Keys:" = "選字鍵:";
|
"Selection Keys:" = "選字鍵:";
|
||||||
|
"Service Menu Editor" = "服務選單編輯器";
|
||||||
"Share alphanumerical mode status across all clients" = "對所有客體應用共用中英文輸入切換狀態";
|
"Share alphanumerical mode status across all clients" = "對所有客體應用共用中英文輸入切換狀態";
|
||||||
"Shift+BackSpace:" = "Shift+退格鍵:";
|
"Shift+BackSpace:" = "Shift+退格鍵:";
|
||||||
"Shift+Letter:" = "Shift+字母鍵:";
|
"Shift+Letter:" = "Shift+字母鍵:";
|
||||||
|
|
Loading…
Reference in New Issue