feat: swap translation languages with Return on empty input
This commit is contained in:
@@ -136,9 +136,9 @@ Notes autosave locally as RTFD packages, including embedded images, under `~/Lib
|
||||
|
||||
## Translation
|
||||
|
||||
Search for **Conjure Translate**, identified by its centered 🌏 icon, and open it. Choose a provider in the pill-shaped header selector, enter text in the search bar, then press Return or click **Translate**. Typing alone never sends text. When the translation is available, the action changes to **Copy**: press Return or click it to copy the full translation and close Conjure. Command-C still copies selected output. Editing the input restores **Translate**.
|
||||
Search for **Conjure Translate**, identified by its centered 🌏 icon, and open it. With empty or whitespace-only input, Return or **Swap languages** reverses the source and target without submitting a request. Enter text to change the action to **Translate**; press Return or click it to submit. Typing alone never sends text. When the translation is available, the action changes to **Copy**: press Return or click it to copy the full translation and close Conjure. Command-C still copies selected output. Editing the input clears the result and restores **Translate**, or **Swap languages** if empty. The action is disabled while translating.
|
||||
|
||||
The footer places **Translate/Copy** and its Return keycap before **Actions**, whose Command and K keys use separate keycaps, matching the launcher.
|
||||
The footer places the current primary action and its Return keycap before **Actions**, whose Command and K keys use separate keycaps, matching the launcher.
|
||||
|
||||
Press Command-P or click the provider selector to expand a searchable action-style popup from its top edge downwards, hiding the indicator until the popup closes. A checkmark marks the current provider. Use Up/Down and Return or click a provider to select it; Escape, Back, or clicking outside closes the popup. Changing providers clears the previous result without submitting a request.
|
||||
|
||||
|
||||
@@ -239,8 +239,11 @@ final class TranslationController: NSViewController {
|
||||
func inputChanged() {
|
||||
cancelRequest()
|
||||
output.string = ""
|
||||
translateButton.title = "Translate"
|
||||
translateButton.toolTip = "Translate the input (Return). Escape dismisses Conjure."
|
||||
let isEmpty = (input?() ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
translateButton.title = isEmpty ? "Swap languages" : "Translate"
|
||||
translateButton.toolTip = isEmpty
|
||||
? "Swap source and target languages (Return)."
|
||||
: "Translate the input (Return). Escape dismisses Conjure."
|
||||
settingsButton.isHidden = true
|
||||
languageButton.title = "\(languageName(sourceLanguage)) → \(languageName(targetLanguage))"
|
||||
output.setAccessibilityLabel("\(languageName(targetLanguage)) translation")
|
||||
@@ -269,6 +272,10 @@ final class TranslationController: NSViewController {
|
||||
|
||||
@objc func performPrimaryAction() {
|
||||
guard task == nil else { return }
|
||||
if (input?() ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
swapLanguages()
|
||||
return
|
||||
}
|
||||
guard !output.string.isEmpty else { translate(); return }
|
||||
pasteboard.clearContents()
|
||||
if pasteboard.setString(output.string, forType: .string) {
|
||||
|
||||
@@ -58,6 +58,26 @@ private func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.fl
|
||||
|
||||
@Suite(.serialized)
|
||||
struct TranslationExecutionTests {
|
||||
@Test @MainActor
|
||||
func emptyPrimaryActionSwapsLanguagesWithoutSubmitting() {
|
||||
_ = NSApplication.shared
|
||||
let suite = "TranslateEmpty.\(UUID().uuidString)"
|
||||
let defaults = UserDefaults(suiteName: suite)!
|
||||
defer { defaults.removePersistentDomain(forName: suite) }
|
||||
let tool = TranslationController(defaults: defaults,
|
||||
myMemory: { _, _, _ in Issue.record("Empty input must not submit"); return "unexpected" })
|
||||
tool.input = { " \n\t" }
|
||||
_ = tool.view
|
||||
let button = descendants(tool.view).compactMap { $0 as? NSButton }
|
||||
.first { $0.action == NSSelectorFromString("performPrimaryAction") }!
|
||||
button.performClick(nil)
|
||||
#expect(tool.sourceLanguage == "ja")
|
||||
#expect(tool.targetLanguage == "en")
|
||||
tool.performPrimaryAction()
|
||||
#expect(tool.sourceLanguage == "en")
|
||||
#expect(tool.targetLanguage == "ja")
|
||||
}
|
||||
|
||||
@Test @MainActor
|
||||
func languageActionsInvalidateOldResultsAndApplyTheSelectedPair() async throws {
|
||||
_ = NSApplication.shared
|
||||
|
||||
Reference in New Issue
Block a user