From 8a36be4964cbcc9bddb4de3b313abe115743ff0f Mon Sep 17 00:00:00 2001 From: tisfeng Date: Tue, 22 Oct 2024 10:09:58 +0800 Subject: [PATCH] refactor: move some general settings to advanced tab (#699) * refactor: move some general settings to advanced tab * chore: update AppleTranslation * refactor: remove AppleTranslation swift package * fix: remove import AppleTranslation * Update Easydict/Swift/Service/Apple/TranslationService/TranslationManager.swift Co-authored-by: Phillip <103433299+phlpsong@users.noreply.github.com> --------- Co-authored-by: Phillip <103433299+phlpsong@users.noreply.github.com> --- Easydict.xcodeproj/project.pbxproj | 37 +- .../xcshareddata/swiftpm/Package.resolved | 11 +- Easydict/App/Localizable.xcstrings | 740 ++++++++++-------- .../Swift/Service/Apple/AppleService.swift | 1 - .../TranslationManager.swift | 63 ++ .../TranslationService.swift | 169 ++++ .../TranslationService/TranslationView.swift | 28 + .../Tabs/TabView/AdvancedTab.swift | 147 +++- .../SettingView/Tabs/TabView/GeneralTab.swift | 146 ++-- Easydict/objc/Service/Apple/EZAppleService.m | 3 - 10 files changed, 876 insertions(+), 469 deletions(-) create mode 100644 Easydict/Swift/Service/Apple/TranslationService/TranslationManager.swift create mode 100644 Easydict/Swift/Service/Apple/TranslationService/TranslationService.swift create mode 100644 Easydict/Swift/Service/Apple/TranslationService/TranslationView.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index ecc0431f9..ec1493007 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -44,7 +44,6 @@ 033C31002A74CECE0095926A /* EZAppleDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 033C30FF2A74CECE0095926A /* EZAppleDictionary.m */; }; 033E181F2C5A970A0099A7B0 /* Vapor in Frameworks */ = {isa = PBXBuildFile; productRef = 033E181E2C5A970A0099A7B0 /* Vapor */; }; 033EAA9F2CBBBE2B004DC199 /* ForceGetSelectedTextType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033EAA9E2CBBBE2B004DC199 /* ForceGetSelectedTextType.swift */; }; - 03404B2E2CC3643F0024CF69 /* AppleTranslation in Frameworks */ = {isa = PBXBuildFile; productRef = 03404B2D2CC3643F0024CF69 /* AppleTranslation */; }; 0340D38E2C8EEEA2004C9910 /* AppleScriptTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0340D38D2C8EEEA2004C9910 /* AppleScriptTask.swift */; }; 0340D3912C8EEEE3004C9910 /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0340D3902C8EEEE3004C9910 /* Data+Extension.swift */; }; 0340D3942C8EEF58004C9910 /* Dictionary+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0340D3932C8EEF58004C9910 /* Dictionary+Extension.swift */; }; @@ -118,6 +117,9 @@ 0396D611292C932F006A11D9 /* EZSelectLanguageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0396D610292C932F006A11D9 /* EZSelectLanguageCell.m */; }; 0396D615292CC4C3006A11D9 /* EZLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0396D614292CC4C3006A11D9 /* EZLocalStorage.m */; }; 0396DE552BB5844A009FD2A5 /* BaseOpenAIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0396DE542BB5844A009FD2A5 /* BaseOpenAIService.swift */; }; + 039785282CC678F400A49087 /* TranslationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039785242CC678F400A49087 /* TranslationManager.swift */; }; + 039785292CC678F400A49087 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039785252CC678F400A49087 /* TranslationService.swift */; }; + 0397852A2CC678F400A49087 /* TranslationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039785262CC678F400A49087 /* TranslationView.swift */; }; 03991158292927E000E1B06D /* EZTitlebar.m in Sources */ = {isa = PBXBuildFile; fileRef = 03991157292927E000E1B06D /* EZTitlebar.m */; }; 03991166292A8A4400E1B06D /* EZTitleBarMoveView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03991165292A8A4400E1B06D /* EZTitleBarMoveView.m */; }; 0399116A292AA2EF00E1B06D /* EZLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 03991169292AA2EF00E1B06D /* EZLayoutManager.m */; }; @@ -524,6 +526,9 @@ 0396D613292CC4C3006A11D9 /* EZLocalStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZLocalStorage.h; sourceTree = ""; }; 0396D614292CC4C3006A11D9 /* EZLocalStorage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZLocalStorage.m; sourceTree = ""; }; 0396DE542BB5844A009FD2A5 /* BaseOpenAIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseOpenAIService.swift; sourceTree = ""; }; + 039785242CC678F400A49087 /* TranslationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationManager.swift; sourceTree = ""; }; + 039785252CC678F400A49087 /* TranslationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationService.swift; sourceTree = ""; }; + 039785262CC678F400A49087 /* TranslationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationView.swift; sourceTree = ""; }; 03991156292927E000E1B06D /* EZTitlebar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZTitlebar.h; sourceTree = ""; }; 03991157292927E000E1B06D /* EZTitlebar.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZTitlebar.m; sourceTree = ""; }; 03991164292A8A4400E1B06D /* EZTitleBarMoveView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZTitleBarMoveView.h; sourceTree = ""; }; @@ -914,7 +919,6 @@ 03B63ABF2A86967800E155ED /* CoreServices.framework in Frameworks */, 038030972B4106800009230C /* CocoaLumberjackSwift in Frameworks */, 038EA1AA2B41169C008A6DD1 /* ZipArchive in Frameworks */, - 03404B2E2CC3643F0024CF69 /* AppleTranslation in Frameworks */, 0364EC8D2C208FB70036B61B /* AXSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1242,6 +1246,7 @@ 036463682CB62B6600D0D6CC /* Apple */ = { isa = PBXGroup; children = ( + 039785272CC678F400A49087 /* TranslationService */, 036463692CB62B8900D0D6CC /* AppleService.swift */, ); path = Apple; @@ -1472,6 +1477,16 @@ path = Storage; sourceTree = ""; }; + 039785272CC678F400A49087 /* TranslationService */ = { + isa = PBXGroup; + children = ( + 039785252CC678F400A49087 /* TranslationService.swift */, + 039785242CC678F400A49087 /* TranslationManager.swift */, + 039785262CC678F400A49087 /* TranslationView.swift */, + ); + path = TranslationService; + sourceTree = ""; + }; 03991155292927A100E1B06D /* Titlebar */ = { isa = PBXGroup; children = ( @@ -2665,7 +2680,6 @@ C4BE8E1B2C72E61B00F53204 /* LaunchAtLogin */, 036806572CA829F100800B76 /* SFSafeSymbols */, 0346F3D52CAECEFC006A6CDF /* AXSwiftExt */, - 03404B2D2CC3643F0024CF69 /* AppleTranslation */, ); productName = Bob; productReference = C99EEB182385796700FEE666 /* Easydict-debug.app */; @@ -2733,7 +2747,6 @@ C4BE8E1A2C72E5C500F53204 /* XCRemoteSwiftPackageReference "LaunchAtLogin-Modern" */, 036806562CA829F100800B76 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, 0346F3D42CAECEFC006A6CDF /* XCRemoteSwiftPackageReference "AXSwiftExt" */, - 03404B2C2CC3643F0024CF69 /* XCRemoteSwiftPackageReference "AppleTranslation" */, ); productRefGroup = C99EEB192385796700FEE666 /* Products */; projectDirPath = ""; @@ -2991,6 +3004,9 @@ 03FA677E2C2EFB10000FEA64 /* LLMStreamService+Configuration.swift in Sources */, 03882F8E29D95044005B5A52 /* ToastWindowController.m in Sources */, 03B0231929231FA6001C7E63 /* SnipViewController.m in Sources */, + 039785282CC678F400A49087 /* TranslationManager.swift in Sources */, + 039785292CC678F400A49087 /* TranslationService.swift in Sources */, + 0397852A2CC678F400A49087 /* TranslationView.swift in Sources */, 039CC910292F86F40037B91E /* NSImage+EZResize.m in Sources */, 03B0232529231FA6001C7E63 /* NSButton+MM.m in Sources */, 03D0434E292886D200E7559E /* EZMiniQueryWindow.m in Sources */, @@ -3616,14 +3632,6 @@ minimumVersion = 4.102.1; }; }; - 03404B2C2CC3643F0024CF69 /* XCRemoteSwiftPackageReference "AppleTranslation" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/tisfeng/AppleTranslation"; - requirement = { - kind = upToNextMinorVersion; - minimumVersion = 1.0.0; - }; - }; 0346F3D42CAECEFC006A6CDF /* XCRemoteSwiftPackageReference "AXSwiftExt" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/s1ntoneli/AXSwiftExt"; @@ -3791,11 +3799,6 @@ package = 033E181D2C5A970A0099A7B0 /* XCRemoteSwiftPackageReference "vapor" */; productName = Vapor; }; - 03404B2D2CC3643F0024CF69 /* AppleTranslation */ = { - isa = XCSwiftPackageProductDependency; - package = 03404B2C2CC3643F0024CF69 /* XCRemoteSwiftPackageReference "AppleTranslation" */; - productName = AppleTranslation; - }; 0346F3D52CAECEFC006A6CDF /* AXSwiftExt */ = { isa = XCSwiftPackageProductDependency; package = 0346F3D42CAECEFC006A6CDF /* XCRemoteSwiftPackageReference "AXSwiftExt" */; diff --git a/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved index 919a5e359..fb03b9076 100644 --- a/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "1b5bf214999fc88f3a79515b2a6f574f8e5d9dc30f91419ecc416ae5a8f4acc9", + "originHash" : "d88b5b8250adbaea6c584fb14d5173d28fde088b92e123e49eb7f087b8d44d3d", "pins" : [ { "identity" : "abseil-cpp-binary", @@ -37,15 +37,6 @@ "version" : "5.0.4" } }, - { - "identity" : "appletranslation", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tisfeng/AppleTranslation", - "state" : { - "revision" : "95e5ab50ebd6e515080bbb3e67b73ddc1c92764d", - "version" : "1.0.1" - } - }, { "identity" : "async-http-client", "kind" : "remoteSourceControl", diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index fc3e26cdf..8cb50a6d8 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -799,40 +799,6 @@ } } }, - "auto_show_query_icon" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Auto show query icon after selecting text" - } - }, - "en-CA" : { - "stringUnit" : { - "state" : "translated", - "value" : "Auto show query icon after selecting text" - } - }, - "sk" : { - "stringUnit" : { - "state" : "translated", - "value" : "Automaticky zobraziť ikonu prekladania po označení textu" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "划词后自动显示查询图标" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "選取文本後自動顯示查詢圖示" - } - } - } - }, "Baidu" : { "extractionState" : "manual", "localizations" : { @@ -1267,40 +1233,6 @@ } } }, - "click_icon_query_info" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Query only when clicking query icon (when main window hidden)" - } - }, - "en-CA" : { - "stringUnit" : { - "state" : "translated", - "value" : "Query only when clicking query icon (when main window hidden)" - } - }, - "sk" : { - "stringUnit" : { - "state" : "translated", - "value" : "Prekladať len po kliknutí na ikonu prekladania (pri skrytom hlavnom okne)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "点击图标时才查询(需隐藏主窗口)" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "僅在點擊查詢圖示時查詢(當主視窗隱藏時)" - } - } - } - }, "collocation" : { "extractionState" : "manual", "localizations" : { @@ -2294,40 +2226,6 @@ } } }, - "force_get_selected_text" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Allow forced text selection (note that it may affect clipboard copying)" - } - }, - "en-CA" : { - "stringUnit" : { - "state" : "translated", - "value" : "Allow forced text selection (note that it may affect clipboard copying)" - } - }, - "sk" : { - "stringUnit" : { - "state" : "translated", - "value" : "Povoliť vynútený výber textu (môže ovplyvniť kopírovanie do schránky)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "允许强制取词(注意,这可能会影响剪贴板复制)" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "允許強制文字選擇(注意可能會影響剪貼簿複製)" - } - } - } - }, "Function not implemented for the current algorithm" : { "comment" : "Error reason", "localizations" : { @@ -2557,40 +2455,6 @@ } } }, - "hide_main_window" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Hide main window at startup" - } - }, - "en-CA" : { - "stringUnit" : { - "state" : "translated", - "value" : "Hide main window at startup" - } - }, - "sk" : { - "stringUnit" : { - "state" : "translated", - "value" : "Skryť hlavné okno pri spustení" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启动后隐藏主窗口" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "啟動時隱藏主視窗" - } - } - } - }, "hide_menu_bar_icon" : { "localizations" : { "en" : { @@ -6645,6 +6509,40 @@ } } }, + "setting.advance.auto_show_query_icon" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auto show query icon after selecting text" + } + }, + "en-CA" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auto show query icon after selecting text" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automaticky zobraziť ikonu prekladania po označení textu" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "划词后自动显示查询图标" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "選取文本後自動顯示查詢圖示" + } + } + } + }, "setting.advance.automatically_remove_code_comment_symbols" : { "localizations" : { "en" : { @@ -6747,6 +6645,40 @@ } } }, + "setting.advance.click_icon_query_info" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Query only when clicking select query icon (when main window hidden)" + } + }, + "en-CA" : { + "stringUnit" : { + "state" : "translated", + "value" : "Query only when clicking select query icon (when main window hidden)" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prekladať len po kliknutí na ikonu vyberania textu (pri skrytom hlavnom okne)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "点击划词查询图标时才查询(需隐藏主窗口)" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "僅在點擊划詞查詢圖示時查詢(當主視窗隱藏時)" + } + } + } + }, "setting.advance.default_tts_service" : { "localizations" : { "en" : { @@ -6850,6 +6782,74 @@ } } }, + "setting.advance.enable_force_get_selected_text" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable Force Get Selected Text" + } + }, + "en-CA" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable Force Get Selected Text" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zapnúť silné získanie vybraného textu" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用强制取词" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "啟用強制取詞" + } + } + } + }, + "setting.advance.enable_force_get_selected_text_desc" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note: This may affect the clipboard content" + } + }, + "en-CA" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note: This may affect the clipboard content." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poznámka: Toto môže ovplyvniť obsah schránky." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "注意,这可能会影响剪贴板内容" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "注意,這可能會影響剪貼板內容" + } + } + } + }, "setting.advance.enable_http_server" : { "localizations" : { "en" : { @@ -7020,70 +7020,138 @@ } } }, - "setting.advance.header.http_server" : { + "setting.advance.header.force_get_selected_text" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "HTTP Server" + "value" : "Force Get Selected Text" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "HTTP Server" + "value" : "Force Get Selected Text" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "HTTP Server" + "value" : "Silné získanie vybraného textu" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "HTTP 服务器" + "value" : "强制取词" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "HTTP 伺服器" + "value" : "強制取詞" } } } }, - "setting.advance.header.query_text_processing" : { + "setting.advance.header.http_server" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Query Text Processing" + "value" : "HTTP Server" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Query Text Processing" + "value" : "HTTP Server" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Spracovanie textu dopytu" + "value" : "HTTP Server" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "查询文本处理" + "value" : "HTTP 服务器" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "查詢文本處理" + "value" : "HTTP 伺服器" + } + } + } + }, + "setting.advance.header.query_text_processing" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Query Text Processing" + } + }, + "en-CA" : { + "stringUnit" : { + "state" : "translated", + "value" : "Query Text Processing" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Spracovanie textu dopytu" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "查询文本处理" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "查詢文本處理" + } + } + } + }, + "setting.advance.hide_main_window" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hide main window at startup" + } + }, + "en-CA" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hide main window at startup" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Skryť hlavné okno pri spustení" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "启动后隐藏主窗口" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "啟動時隱藏主視窗" } } } @@ -7156,1058 +7224,1058 @@ } } }, - "setting.advance.replace_with_translation" : { + "setting.advance.mouse_query.adjust_pop_button_origin" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Use Replace with Translation in compatibility mode" + "value" : "Adjust Query Icon Position to avoid conflict with PopClip" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Use Replace with Translation in compatibility mode" + "value" : "Adjust Query Icon Position to avoid conflict with PopClip" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Použiť Nahradiť prekladom v režime kompatibility" + "value" : "Uprav pozíciu ikony vyberania textu pre vyhnutie sa konfliktu s PopClip" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用兼容模式进行译文替换" + "value" : "调整划词查询图标位置(避免和 PopClip 显示冲突)" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "在相容模式中使用以翻譯取代" + "value" : "調整划詞查詢圖示位置以避免與 PopClip 衝突" } } } }, - "setting.advance.replace_with_translation_desc" : { + "setting.advance.mouse_select_query.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "If using Repalce with Translation fails in some applications, try turning on compatibility mode, which will use Copy + Paste to ensure successful replacement." + "value" : "Mouse Select Query" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "If using Replace with Translation fails in some applications, try turning on compatibility mode, which will use Copy + Paste to ensure successful replacement." + "value" : "Mouse Select Query" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Ak používanie Nahradiť prekladom zlyhá v niektorých aplikáciách, skús zapnúť režim kompatibility, ktorý použije funkcie Kopírovať + Vložiť na zabezpečenie úspešnej výmeny." + "value" : "Vyber text myšou" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "如果在某些应用中使用译文替换失败,请尝试开启兼容模式,它将会使用复制+粘贴方式确保替换成功。" + "value" : "鼠标划词查询" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "如果在某些應用程式中使用「以翻譯取代」功能失敗,請嘗試開啟相容模式,此模式會使用拷貝 + 貼上來確保成功取代。" + "value" : "滑鼠划詞查詢" } } } }, - "setting.advance.youdao_ocr" : { + "setting.advance.pin_window_when_showing" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Youdao OCR recognition" + "value" : "Automatically pin when the window is displayed." } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Youdao OCR recognition" + "value" : "Automatically pin when the window is displayed." } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Youdao OCR rozpoznávanie" + "value" : "Automatické pripnutie po zobrazení okna." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "有道 OCR 识别" + "value" : "当窗口显示时自动钉住" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "有道 OCR 辨識" + "value" : "顯示視窗時自動釘選" } } } }, - "setting.advance.youdao_ocr_desc" : { + "setting.advance.replace_with_translation" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Use the Youdao OCR for identification after a default OCR failure" + "value" : "Use Replace with Translation in compatibility mode" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Use the Youdao OCR for identification after a default OCR failure" + "value" : "Use Replace with Translation in compatibility mode" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Použiť Youdao OCR na identifikáciu po zlyhaní štandardného OCR" + "value" : "Použiť Nahradiť prekladom v režime kompatibility" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在默认OCR识别失败后使用有道OCR进行识别" + "value" : "使用兼容模式进行译文替换" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "預設 OCR 識別失敗後使用有道 OCR 進行識別" + "value" : "在相容模式中使用以翻譯取代" } } } }, - "setting.disabled.import_app_error.message" : { - "extractionState" : "manual", + "setting.advance.replace_with_translation_desc" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Unable to add Application" + "value" : "If using Repalce with Translation fails in some applications, try turning on compatibility mode, which will use Copy + Paste to ensure successful replacement." } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Unable to add Application" + "value" : "If using Replace with Translation fails in some applications, try turning on compatibility mode, which will use Copy + Paste to ensure successful replacement." } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Nie je možné pridať aplikáciu" + "value" : "Ak používanie Nahradiť prekladom zlyhá v niektorých aplikáciách, skús zapnúť režim kompatibility, ktorý použije funkcie Kopírovať + Vložiť na zabezpečenie úspešnej výmeny." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "无法添加应用" + "value" : "如果在某些应用中使用译文替换失败,请尝试开启兼容模式,它将会使用复制+粘贴方式确保替换成功。" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "無法新增應用程式" + "value" : "如果在某些應用程式中使用「以翻譯取代」功能失敗,請嘗試開啟相容模式,此模式會使用拷貝 + 貼上來確保成功取代。" } } } }, - "setting.general.app_setting.header" : { + "setting.advance.window_management.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "App Setting" + "value" : "Window Management" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "App Setting" + "value" : "Window Management" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Nastavenie aplikácie" + "value" : "Správa okna" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "应用设置" + "value" : "窗口管理" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "應用程式設定" + "value" : "視窗管理" } } } }, - "setting.general.appearance.light_dark_appearance" : { + "setting.advance.window.fixed_window_position" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Appearance" + "value" : "Floating Window Position" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Appearance" + "value" : "Floating Window Position" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Vzhľad" + "value" : "Pozícia plávajúceho okna" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "外观" + "value" : "侧悬浮窗口位置" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "外觀" + "value" : "浮動視窗位置" } } } }, - "setting.general.auto_copy.header" : { + "setting.advance.window.mouse_select_translate_window_type" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Auto Copy" + "value" : "Mouse Window Type" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Auto Copy" + "value" : "Mouse Window Type" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Automatické kopírovanie" + "value" : "Typ okna myši" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动复制" + "value" : "鼠标划词窗口类型" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "自動拷貝" + "value" : "滑鼠視窗類型" } } } }, - "setting.general.auto_query.header" : { + "setting.advance.window.shortcut_select_translate_window_type" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Auto Query" + "value" : "Shortcut Window Type" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Auto Query" + "value" : "Shortcut Window Type" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Automatické prekladanie" + "value" : "Typ okna skratky" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动查询" + "value" : "快捷键划词窗口类型" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "自動查詢" + "value" : "快速鍵視窗類型" } } } }, - "setting.general.font.font_size.label" : { + "setting.advance.youdao_ocr" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Font Size" + "value" : "Youdao OCR recognition" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Font Size" + "value" : "Youdao OCR recognition" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Veľkosť písma" + "value" : "Youdao OCR rozpoznávanie" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "字体大小" + "value" : "有道 OCR 识别" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "字體大小" + "value" : "有道 OCR 辨識" } } } }, - "setting.general.font.header" : { + "setting.advance.youdao_ocr_desc" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Font" + "value" : "Use the Youdao OCR for identification after a default OCR failure" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Font" + "value" : "Use the Youdao OCR for identification after a default OCR failure" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Písmo" + "value" : "Použiť Youdao OCR na identifikáciu po zlyhaní štandardného OCR" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "字体" + "value" : "在默认OCR识别失败后使用有道OCR进行识别" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "字體" + "value" : "預設 OCR 識別失敗後使用有道 OCR 進行識別" } } } }, - "setting.general.input.header" : { + "setting.disabled.import_app_error.message" : { + "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Input Field" + "value" : "Unable to add Application" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Input Field" + "value" : "Unable to add Application" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Vstupné pole" + "value" : "Nie je možné pridať aplikáciu" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "输入框" + "value" : "无法添加应用" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "輸入欄位" + "value" : "無法新增應用程式" } } } }, - "setting.general.language.duplicated_alert %@%@%@" : { + "setting.general.app_setting.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "The first language should not be the same as the second language (%1$@). The %2$@ was replaced with %3$@." + "value" : "App Setting" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "The first language should not be the same as the second language (%1$@). The %2$@ was replaced with %3$@." + "value" : "App Setting" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Prvý jazyk by nemal byť rovnaký ako druhý jazyk (%1$@). %2$@ bol nahradený %3$@." + "value" : "Nastavenie aplikácie" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "第一语言不能与第二语言相同(%1$@)。%2$@已被替换为%3$@。" + "value" : "应用设置" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "第一語言不應與第二語言(%1$@)相同。%2$@ 已被 %3$@ 取代。" + "value" : "應用程式設定" } } } }, - "setting.general.language.duplicated_alert.field.first" : { + "setting.general.appearance.light_dark_appearance" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "first language" + "value" : "Appearance" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "first language" + "value" : "Appearance" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "prvý jazyk" + "value" : "Vzhľad" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "第二语言" + "value" : "外观" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "第一語言" + "value" : "外觀" } } } }, - "setting.general.language.duplicated_alert.field.second" : { + "setting.general.auto_copy.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "second language" + "value" : "Auto Copy" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "second language" + "value" : "Auto Copy" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "druhý jazyk" + "value" : "Automatické kopírovanie" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "第一语言" + "value" : "自动复制" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "第二語言" + "value" : "自動拷貝" } } } }, - "setting.general.language.duplicated_alert.title" : { + "setting.general.auto_query.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Language Duplicated" + "value" : "Auto Query" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Language Duplicated" + "value" : "Auto Query" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Duplikovaný jazyk" + "value" : "Automatické prekladanie" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "语言重复" + "value" : "自动查询" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "語言重複" + "value" : "自動查詢" } } } }, - "setting.general.language.first_language" : { + "setting.general.font.font_size.label" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "First Language" + "value" : "Font Size" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "First Language" + "value" : "Font Size" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Prvý jazyk" + "value" : "Veľkosť písma" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "第一语言" + "value" : "字体大小" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "第一語言" + "value" : "字體大小" } } } }, - "setting.general.language.header" : { + "setting.general.font.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Language" + "value" : "Font" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Language" + "value" : "Font" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Jazyk" + "value" : "Písmo" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "语言" + "value" : "字体" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "語言" + "value" : "字體" } } } }, - "setting.general.language.language_detect_optimize" : { + "setting.general.input.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Language Detection" + "value" : "Input Field" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Language Detection" + "value" : "Input Field" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Detekcia jazyka" + "value" : "Vstupné pole" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "语种识别" + "value" : "输入框" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "語言偵測" + "value" : "輸入欄位" } } } }, - "setting.general.language.second_language" : { + "setting.general.language" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Second Language" + "value" : "Language" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Second Language" + "value" : "Language" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Druhý jazyk" + "value" : "Jazyk" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "第二语言" + "value" : "语言" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "第二語言" + "value" : "語言" } } } }, - "setting.general.mouse_query.adjust_pop_button_origin" : { + "setting.general.language.duplicated_alert %@%@%@" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Adjust Query Icon Position to avoid conflict with PopClip" + "value" : "The first language should not be the same as the second language (%1$@). The %2$@ was replaced with %3$@." } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Adjust Query Icon Position to avoid conflict with PopClip" + "value" : "The first language should not be the same as the second language (%1$@). The %2$@ was replaced with %3$@." } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Uprav pozíciu ikony prekladu pre vyhnutie sa konfliktu s PopClip" + "value" : "Prvý jazyk by nemal byť rovnaký ako druhý jazyk (%1$@). %2$@ bol nahradený %3$@." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "调整查询图标位置(避免和 PopClip 显示冲突)" + "value" : "第一语言不能与第二语言相同(%1$@)。%2$@已被替换为%3$@。" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "調整查詢圖示位置以避免與 PopClip 衝突" + "value" : "第一語言不應與第二語言(%1$@)相同。%2$@ 已被 %3$@ 取代。" } } } }, - "setting.general.mouse_query.header" : { + "setting.general.language.duplicated_alert.field.first" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Query with Mouse" + "value" : "first language" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Query with Mouse" + "value" : "first language" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Preklad myšou" + "value" : "prvý jazyk" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "鼠标查询" + "value" : "第二语言" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "滑鼠查詢" + "value" : "第一語言" } } } }, - "setting.general.other.header" : { - "extractionState" : "manual", + "setting.general.language.duplicated_alert.field.second" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Other" + "value" : "second language" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Other" + "value" : "second language" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Iné" + "value" : "druhý jazyk" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "其他" + "value" : "第一语言" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "其他" + "value" : "第二語言" } } } }, - "setting.general.pin_window_when_showing" : { + "setting.general.language.duplicated_alert.title" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Automatically pin when the window is displayed." + "value" : "Language Duplicated" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Automatically pin when the window is displayed." + "value" : "Language Duplicated" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Automatické pripnutie po zobrazení okna." + "value" : "Duplikovaný jazyk" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "当窗口显示时自动钉住" + "value" : "语言重复" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "顯示視窗時自動釘選" + "value" : "語言重複" } } } }, - "setting.general.query_language.header" : { + "setting.general.language.first_language" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Query Langauge" + "value" : "First Language" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Query Langauge" + "value" : "First Language" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Jazyk prekladu" + "value" : "Prvý jazyk" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "查询语言" + "value" : "第一语言" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "查詢語言" + "value" : "第一語言" } } } }, - "setting.general.quick_link.header" : { + "setting.general.language.language_detect_optimize" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Quick Link" + "value" : "Language Detection" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Quick Link" + "value" : "Language Detection" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Rýchly odkaz" + "value" : "Detekcia jazyka" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷功能" + "value" : "语种识别" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "快速連結" + "value" : "語言偵測" } } } }, - "setting.general.voice.auto_play_word_audio" : { + "setting.general.language.second_language" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Auto play pronunciation after querying English words" + "value" : "Second Language" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Auto play pronunciation after querying English words" + "value" : "Second Language" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Automaticky prehrať výslovnosť po preklade anglických slov" + "value" : "Druhý jazyk" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "查询英语单词后自动播放发音" + "value" : "第二语言" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "查詢英文單字後自動播放發音" + "value" : "第二語言" } } } }, - "setting.general.window.fixed_window_position" : { + "setting.general.other.header" : { + "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Floating Window Position" + "value" : "Other" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Floating Window Position" + "value" : "Other" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Pozícia plávajúceho okna" + "value" : "Iné" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "侧悬浮窗口位置" + "value" : "其他" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "浮動視窗位置" + "value" : "其他" } } } }, - "setting.general.window.mouse_select_translate_window_type" : { + "setting.general.query_language.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Mouse Window Type" + "value" : "Query Langauge" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Mouse Window Type" + "value" : "Query Langauge" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Typ okna myši" + "value" : "Jazyk prekladu" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "鼠标划词窗口类型" + "value" : "查询语言" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "滑鼠視窗類型" + "value" : "查詢語言" } } } }, - "setting.general.window.shortcut_select_translate_window_type" : { + "setting.general.quick_link.header" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Shortcut Window Type" + "value" : "Quick Link" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Shortcut Window Type" + "value" : "Quick Link" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Typ okna skratky" + "value" : "Rýchly odkaz" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷键划词窗口类型" + "value" : "快捷功能" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "快速鍵視窗類型" + "value" : "快速連結" } } } }, - "setting.general.windows.header" : { + "setting.general.voice.auto_play_word_audio" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Window" + "value" : "Auto play pronunciation after querying English words" } }, "en-CA" : { "stringUnit" : { "state" : "translated", - "value" : "Window" + "value" : "Auto play pronunciation after querying English words" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Okno" + "value" : "Automaticky prehrať výslovnosť po preklade anglických slov" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "窗口" + "value" : "查询英语单词后自动播放发音" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "視窗" + "value" : "查詢英文單字後自動播放發音" } } } diff --git a/Easydict/Swift/Service/Apple/AppleService.swift b/Easydict/Swift/Service/Apple/AppleService.swift index 89eb48a39..807951b53 100644 --- a/Easydict/Swift/Service/Apple/AppleService.swift +++ b/Easydict/Swift/Service/Apple/AppleService.swift @@ -6,7 +6,6 @@ // Copyright © 2024 izual. All rights reserved. // -import AppleTranslation import Foundation import Testing import Translation diff --git a/Easydict/Swift/Service/Apple/TranslationService/TranslationManager.swift b/Easydict/Swift/Service/Apple/TranslationService/TranslationManager.swift new file mode 100644 index 000000000..516b4a720 --- /dev/null +++ b/Easydict/Swift/Service/Apple/TranslationService/TranslationManager.swift @@ -0,0 +1,63 @@ +// +// TranslationManager.swift +// AppleTranslation +// +// Created by tisfeng on 2024/10/10. +// Copyright © 2024 izual. All rights reserved. +// + +import Foundation +import Translation + +// MARK: - TranslationManager + +@available(macOS 15.0, *) +class TranslationManager: ObservableObject { + // MARK: Internal + + @Published var sourceText = "" + @Published var targetText = "" + @Published var configuration: TranslationSession.Configuration? + + @MainActor + func translate( + text: String, + sourceLanguage: Locale.Language?, + targetLanguage: Locale.Language? + ) async throws + -> TranslationSession.Response { + sourceText = text + + return try await withCheckedThrowingContinuation { continuation in + translationContinuation = continuation + + if configuration == nil { + configuration = .init(source: sourceLanguage, target: targetLanguage) + return + } + + configuration?.source = sourceLanguage + configuration?.target = targetLanguage + configuration?.invalidate() + } + } + + func performTranslation(_ session: TranslationSession) { + Task { + do { + let response = try await session.translate(sourceText) + await MainActor.run { + self.targetText = response.targetText + } + translationContinuation?.resume(returning: response) + } catch { + translationContinuation?.resume(throwing: error) + } + translationContinuation = nil + } + } + + // MARK: Private + + private var translationContinuation: CheckedContinuation? +} diff --git a/Easydict/Swift/Service/Apple/TranslationService/TranslationService.swift b/Easydict/Swift/Service/Apple/TranslationService/TranslationService.swift new file mode 100644 index 000000000..a73900d8a --- /dev/null +++ b/Easydict/Swift/Service/Apple/TranslationService/TranslationService.swift @@ -0,0 +1,169 @@ +// +// TranslationService.swift +// AppleTranslation +// +// Created by tisfeng on 2024/10/10. +// Copyright © 2024 izual. All rights reserved. +// + +import Foundation +import SwiftUI +import Translation + +// MARK: - TranslationService + +@objcMembers +@available(macOS 15.0, *) +public class TranslationService: NSObject { + // MARK: Lifecycle + + @MainActor + public init( + attachedWindow: NSWindow? = nil, + configuration: TranslationSession.Configuration? = nil + ) { + self.attachedWindow = attachedWindow + self.configuration = configuration + super.init() + setupTranslationView() + } + + /// Initializer for objc, since objc cannot use Swift TranslationSession.Configuration. + /// + /// - Note: If attachedWindow is nil, the translation view will be attached to the translationWindow we created. + @MainActor + public convenience init(attachedWindow: NSWindow? = nil) { + self.init(attachedWindow: attachedWindow, configuration: nil) + } + + // MARK: Public + + public var enableTranslateSameLanguage = false + public var configuration: TranslationSession.Configuration? + + /// The window that the translation view is attached to. + /// + /// - Note: If attachedWindow is nil, the translation view will be attached to the translationWindow we created. + public var attachedWindow: NSWindow? + + public var translationView: NSView { + translationController.view + } + + /// Translate text with specified source and target languages. + /// + /// If no languages are provided, it uses the current configuration. + public func translate( + text: String, + sourceLanguage: Locale.Language? = nil, + targetLanguage: Locale.Language? = nil + ) async throws + -> TranslationSession.Response { + let source = sourceLanguage ?? configuration?.source + let target = targetLanguage ?? configuration?.target + + do { + // Check if the translation is ready for use. + let isReady = try await translationIsReadyforUse(text: text, from: source, to: target) + await MainActor.run { + translationWindow?.alphaValue = isReady ? 0 : 1 + } + } catch { + await MainActor.run { + translationWindow?.level = .floating + } + } + + do { + return try await manager.translate( + text: text, + sourceLanguage: source, + targetLanguage: target + ) + } catch { + guard let translationError = error as? TranslationError else { throw error } + + switch translationError { + case .unsupportedLanguagePairing: + if source == target, enableTranslateSameLanguage { + return TranslationSession.Response( + sourceLanguage: source ?? .init(identifier: ""), + targetLanguage: target ?? .init(identifier: ""), + sourceText: text, + targetText: text + ) + } + + fallthrough + + default: + throw error + } + } + } + + /// Translate text with language codes, providing a more flexible api. + /// + /// - Parameters + /// - sourceLanguageCode: ISO 639 code, such as zh, en, etc. + /// + /// - Note: Currently Apple Translate does not support language script, so zh-Hans and zh-Hant is the same as zh. + public func translate( + text: String, + sourceLanguageCode: String, + targetLanguageCode: String + ) async throws + -> String { + let response = try await translate( + text: text, + sourceLanguage: .init(identifier: sourceLanguageCode), + targetLanguage: .init(identifier: targetLanguageCode) + ) + return response.targetText + } + + // MARK: Private + + private let manager = TranslationManager() + private var translationWindow: NSWindow? + + private lazy var translationController = NSHostingController( + rootView: TranslationView(manager: manager) + ) + + /// Check if the translation is ready for use. + private func translationIsReadyforUse( + text: String, from source: Locale.Language?, to target: Locale.Language? + ) async throws + -> Bool { + let status = try await LanguageAvailability().status(for: text, from: source, to: target) + return status == .installed + } + + @MainActor + private func setupTranslationView() { + // TranslationView must be added to a window, otherwise it will not work. + if let attachedWindow { + let translationView = translationController.view + attachedWindow.contentView?.addSubview(translationView) + translationView.isHidden = true + } else { + translationWindow = NSWindow(contentViewController: translationController) + translationWindow?.title = "Translation" + translationWindow?.setContentSize(CGSize(width: 200, height: 200)) + translationWindow?.makeKeyAndOrderFront(nil) + } + } +} + +@available(macOS 15.0, *) +extension LanguageAvailability { + public func status(for text: String, from source: Locale.Language?, to target: Locale.Language?) + async throws + -> LanguageAvailability.Status { + if let source { + return await status(from: source, to: target) + } + return try await status(for: text, to: target) + } +} diff --git a/Easydict/Swift/Service/Apple/TranslationService/TranslationView.swift b/Easydict/Swift/Service/Apple/TranslationService/TranslationView.swift new file mode 100644 index 000000000..965aca18b --- /dev/null +++ b/Easydict/Swift/Service/Apple/TranslationService/TranslationView.swift @@ -0,0 +1,28 @@ +// +// TranslationExample.swift +// AppleTranslation +// +// Created by tisfeng on 2024/10/10. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI +import Translation + +// MARK: - TranslationView + +@available(macOS 15.0, *) +struct TranslationView: View { + @ObservedObject var manager: TranslationManager + + var body: some View { + VStack { + TextField("", text: $manager.sourceText) + Text(manager.targetText) + } + .padding() + .translationTask(manager.configuration) { session in + manager.performTranslation(session) + } + } +} diff --git a/Easydict/Swift/View/SettingView/Tabs/TabView/AdvancedTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/AdvancedTab.swift index bcff77536..0c4cd0437 100644 --- a/Easydict/Swift/View/SettingView/Tabs/TabView/AdvancedTab.swift +++ b/Easydict/Swift/View/SettingView/Tabs/TabView/AdvancedTab.swift @@ -24,11 +24,13 @@ struct AdvancedTab: View { ) } } + + // Items image color order: blue, green, orange, purple, red Section { Picker( selection: $defaultTTSServiceType, label: AdvancedTabItemView( - color: .orange, + color: .blue, systemImage: SFSymbol.ellipsisBubbleFill.rawValue, labelText: "setting.advance.default_tts_service" ) @@ -40,7 +42,7 @@ struct AdvancedTab: View { } Toggle(isOn: $disableTipsView) { AdvancedTabItemView( - color: .orange, + color: .green, systemImage: SFSymbol.lightbulbFill.rawValue, labelText: "setting.advance.disable_tips_view" ) @@ -56,7 +58,7 @@ struct AdvancedTab: View { } Toggle(isOn: $replaceWithTranslationInCompatibilityMode) { AdvancedTabItemView( - color: .cyan, + color: .purple, systemImage: SFSymbol.arrowForwardSquare.rawValue, labelText: "setting.advance.replace_with_translation", subtitleText: "setting.advance.replace_with_translation_desc" @@ -67,18 +69,30 @@ struct AdvancedTab: View { if #available(macOS 15.0, *) { Toggle(isOn: $enableLocalAppleTranslation) { AdvancedTabItemView( - color: .cyan, + color: .red, systemImage: SFSymbol.appleLogo.rawValue, labelText: "setting.advance.apple_offline_translation", subtitleText: "setting.advance.apple_offline_translation_desc" ) } } + } + + // Force get selected text + Section { + Toggle(isOn: $enableForceGetSelectedText) { + AdvancedTabItemView( + color: .blue, + systemImage: SFSymbol.characterCursorIbeam.rawValue, + labelText: "setting.advance.enable_force_get_selected_text", + subtitleText: "setting.advance.enable_force_get_selected_text_desc" + ) + } Picker( selection: $forceGetSelectedTextType, label: AdvancedTabItemView( - color: .cyan, + color: .green, systemImage: SFSymbol.highlighter.rawValue, labelText: "setting.advance.force_get_selected_text_type" ) @@ -88,26 +102,58 @@ struct AdvancedTab: View { .tag(option) } } + } header: { + Text("setting.advance.header.force_get_selected_text") } + // Mouse query icon + Section { + Toggle(isOn: $autoSelectText) { + AdvancedTabItemView( + color: .blue, + systemImage: SFSymbol.cursorarrowRays.rawValue, + labelText: "setting.advance.auto_show_query_icon" + ) + } + + Toggle(isOn: $clickQuery) { + AdvancedTabItemView( + color: .green, + systemImage: SFSymbol.cursorarrowClick.rawValue, + labelText: "setting.advance.click_icon_query_info" + ) + } + + Toggle(isOn: $adjustPopButtonOrigin) { + AdvancedTabItemView( + color: .orange, + systemImage: SFSymbol.arrowUpAndDownAndArrowLeftAndRight.rawValue, + labelText: "setting.advance.mouse_query.adjust_pop_button_origin" + ) + } + } header: { + Text("setting.advance.mouse_select_query.header") + } + + // Query text processing Section { Toggle(isOn: $replaceNewlineWithSpace) { AdvancedTabItemView( - color: .indigo, + color: .blue, systemImage: SFSymbol.arrowForwardSquare.rawValue, labelText: "setting.advance.automatically_replace_newline_with_space" ) } Toggle(isOn: $automaticallyRemoveCodeCommentSymbols) { AdvancedTabItemView( - color: .indigo, + color: .green, systemImage: SFSymbol.chevronLeftForwardslashChevronRight.rawValue, labelText: "setting.advance.automatically_remove_code_comment_symbols" ) } Toggle(isOn: $automaticWordSegmentation) { AdvancedTabItemView( - color: .indigo, + color: .purple, systemImage: SFSymbol.textWordSpacing.rawValue, labelText: "setting.advance.automatically_split_words" ) @@ -125,6 +171,70 @@ struct AdvancedTab: View { } } + // Windows management + Section { + Picker( + selection: $mouseSelectTranslateWindowType, + label: AdvancedTabItemView( + color: .blue, + systemImage: SFSymbol.cursorarrowRays.rawValue, + labelText: "setting.advance.window.mouse_select_translate_window_type" + ) + ) { + ForEach(EZWindowType.availableOptions, id: \.rawValue) { option in + Text(option.localizedStringResource) + .tag(option) + } + } + + Picker( + selection: $shortcutSelectTranslateWindowType, + label: AdvancedTabItemView( + color: .green, + systemImage: SFSymbol.keyboardFill.rawValue, + labelText: "setting.advance.window.shortcut_select_translate_window_type" + ) + ) { + ForEach(EZWindowType.availableOptions, id: \.rawValue) { option in + Text(option.localizedStringResource) + .tag(option) + } + } + + Picker( + selection: $fixedWindowPosition, + label: AdvancedTabItemView( + color: .orange, + systemImage: SFSymbol.arrowUpLeftAndArrowDownRight.rawValue, + labelText: "setting.advance.window.fixed_window_position" + ) + ) { + ForEach(EZShowWindowPosition.allCases, id: \.rawValue) { option in + Text(option.localizedStringResource) + .tag(option) + } + } + + Toggle(isOn: $pinWindowWhenDisplayed) { + AdvancedTabItemView( + color: .purple, + systemImage: SFSymbol.pinFill.rawValue, + labelText: "setting.advance.pin_window_when_showing" + ) + } + + Toggle(isOn: $hideMainWindow) { + AdvancedTabItemView( + color: .red, + systemImage: SFSymbol.eyeSlashFill.rawValue, + labelText: "setting.advance.hide_main_window" + ) + } + } header: { + Text("setting.advance.window_management.header") + } + + // HTTP server Section { Toggle(isOn: $enableHTTPServer) { AdvancedTabItemView( @@ -155,24 +265,39 @@ struct AdvancedTab: View { // MARK: Private - @Default(.defaultTTSServiceType) private var defaultTTSServiceType @Default(.enableBetaFeature) private var enableBetaFeature + + @Default(.defaultTTSServiceType) private var defaultTTSServiceType @Default(.disableTipsView) private var disableTipsView @Default(.enableYoudaoOCR) private var enableYoudaoOCR @Default(.replaceWithTranslationInCompatibilityMode) private var replaceWithTranslationInCompatibilityMode + @Default(.enableAppleOfflineTranslation) private var enableLocalAppleTranslation + // Force get selected text + @Default(.enableForceGetSelectedText) private var enableForceGetSelectedText @Default(.forceGetSelectedTextType) private var forceGetSelectedTextType + // Mouse select query + @Default(.autoSelectText) private var autoSelectText + @Default(.clickQuery) private var clickQuery + @Default(.adjustPopButtonOrigin) private var adjustPopButtonOrigin + + // Query text processing @Default(.replaceNewlineWithSpace) var replaceNewlineWithSpace: Bool @Default(.automaticallyRemoveCodeCommentSymbols) var automaticallyRemoveCodeCommentSymbols: Bool @Default(.automaticWordSegmentation) var automaticWordSegmentation: Bool + // Windows management + @Default(.fixedWindowPosition) private var fixedWindowPosition + @Default(.mouseSelectTranslateWindowType) private var mouseSelectTranslateWindowType + @Default(.shortcutSelectTranslateWindowType) private var shortcutSelectTranslateWindowType + @Default(.pinWindowWhenDisplayed) private var pinWindowWhenDisplayed + @Default(.hideMainWindow) private var hideMainWindow + @Default(.enableHTTPServer) private var enableHTTPServer @Default(.httpPort) private var httpPort - @Default(.enableAppleOfflineTranslation) private var enableLocalAppleTranslation - /// Returns Color.green if `enableHTTPServer` is true, returns Color.red otherwise. private func getHttpIconColor() -> Color { enableHTTPServer ? .green : .red diff --git a/Easydict/Swift/View/SettingView/Tabs/TabView/GeneralTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/GeneralTab.swift index 965ebe4bb..e8537e613 100644 --- a/Easydict/Swift/View/SettingView/Tabs/TabView/GeneralTab.swift +++ b/Easydict/Swift/View/SettingView/Tabs/TabView/GeneralTab.swift @@ -43,67 +43,28 @@ struct GeneralTab: View { Form { Section { FirstAndSecondLanguageSettingView() - Picker("setting.general.language.language_detect_optimize", selection: $languageDetectOptimize) { - ForEach(LanguageDetectOptimize.allCases, id: \.rawValue) { option in - Text(option.localizedStringResource) - .tag(option) - } - } - } header: { - Text("setting.general.query_language.header") - } - - Section { - Toggle("auto_show_query_icon", isOn: $autoSelectText) - Toggle("force_get_selected_text", isOn: $enableForceGetSelectedText) - Toggle("click_icon_query_info", isOn: $clickQuery) - Toggle( - "setting.general.mouse_query.adjust_pop_button_origin", - isOn: $adjustPopButtonOrigin - ) // 调整查询图标位置: - } header: { - Text("setting.general.mouse_query.header") - } - - Section { Picker( - "setting.general.window.mouse_select_translate_window_type", - selection: $mouseSelectTranslateWindowType + "setting.general.language.language_detect_optimize", + selection: $languageDetectOptimize ) { - ForEach(EZWindowType.availableOptions, id: \.rawValue) { option in - Text(option.localizedStringResource) - .tag(option) - } - } - Picker( - "setting.general.window.shortcut_select_translate_window_type", - selection: $shortcutSelectTranslateWindowType - ) { - ForEach(EZWindowType.availableOptions, id: \.rawValue) { option in - Text(option.localizedStringResource) - .tag(option) - } - } - Picker("setting.general.window.fixed_window_position", selection: $fixedWindowPosition) { - ForEach(EZShowWindowPosition.allCases, id: \.rawValue) { option in + ForEach(LanguageDetectOptimize.allCases, id: \.rawValue) { option in Text(option.localizedStringResource) .tag(option) } } - Toggle(isOn: $pinWindowWhenDisplayed) { - Text("setting.general.pin_window_when_showing") - } - Toggle(isOn: $hideMainWindow) { - Text("hide_main_window") - } } header: { - Text("setting.general.windows.header") + Text("setting.general.query_language.header") } Section { Toggle("clear_input_when_translating", isOn: $clearInput) - Toggle("keep_prev_result_when_selected_text_is_empty", isOn: $keepPrevResultWhenEmpty) - Toggle("select_query_text_when_window_activate", isOn: $selectQueryTextWhenWindowActivate) + Toggle( + "keep_prev_result_when_selected_text_is_empty", isOn: $keepPrevResultWhenEmpty + ) + Toggle( + "select_query_text_when_window_activate", + isOn: $selectQueryTextWhenWindowActivate + ) } header: { Text("setting.general.input.header") } @@ -112,7 +73,7 @@ struct GeneralTab: View { Toggle("auto_query_ocr_text", isOn: $autoQueryOCRText) Toggle("auto_query_selected_text", isOn: $autoQuerySelectedText) Toggle("auto_query_pasted_text", isOn: $autoQueryPastedText) - Toggle("setting.general.voice.auto_play_word_audio", isOn: $autoPlayAudio) // 查询英语单词后自动播放发音 + Toggle("setting.general.voice.auto_play_word_audio", isOn: $autoPlayAudio) } header: { Text("setting.general.auto_query.header") } @@ -135,13 +96,15 @@ struct GeneralTab: View { } Section { - Picker("setting.general.language.header", selection: $languageState.language) { + Picker("setting.general.language", selection: $languageState.language) { ForEach(LanguageState.LanguageType.allCases, id: \.rawValue) { language in Text(language.name) .tag(language) } } - Picker("setting.general.appearance.light_dark_appearance", selection: $appearanceType) { + Picker( + "setting.general.appearance.light_dark_appearance", selection: $appearanceType + ) { ForEach(AppearenceType.allCases, id: \.rawValue) { option in Text(option.title) .tag(option) @@ -173,17 +136,19 @@ struct GeneralTab: View { logSettings(["launch_at_startup": newValue]) } - Toggle(isOn: $hideMenuBarIcon.didSet(execute: { state in - if state { - // user is not set input shortcut and selection shortcut not allow hide menu bar - if !shortcutsHaveSetuped { - Defaults[.hideMenuBarIcon] = false - showRefuseAlert = true - } else { - showHideMenuBarIconAlert = true + Toggle( + isOn: $hideMenuBarIcon.didSet(execute: { state in + if state { + // user is not set input shortcut and selection shortcut not allow hide menu bar + if !shortcutsHaveSetuped { + Defaults[.hideMenuBarIcon] = false + showRefuseAlert = true + } else { + showHideMenuBarIconAlert = true + } } - } - })) { + }) + ) { Text("hide_menu_bar_icon") } Picker( @@ -202,11 +167,14 @@ struct GeneralTab: View { } Section { - let bindingFontSize = Binding(get: { - Double(fontSizeOptionIndex) - }, set: { newValue in - fontSizeOptionIndex = UInt(newValue) - }) + let bindingFontSize = Binding( + get: { + Double(fontSizeOptionIndex) + }, + set: { newValue in + fontSizeOptionIndex = UInt(newValue) + } + ) Slider(value: bindingFontSize, in: 0.0 ... 4.0, step: 1) { Text("setting.general.font.font_size.label") } minimumValueLabel: { @@ -250,46 +218,37 @@ struct GeneralTab: View { // MARK: Private - @EnvironmentObject private var languageState: LanguageState - @Default(.autoSelectText) private var autoSelectText - @Default(.enableForceGetSelectedText) private var enableForceGetSelectedText - @Default(.clickQuery) private var clickQuery - @Default(.adjustPopButtonOrigin) private var adjustPopButtonOrigin + // Query language + @Default(.languageDetectOptimize) private var languageDetectOptimize + // Input textfield @Default(.clearQueryWhenInputTranslate) private var clearInput @Default(.keepPrevResultWhenSelectTranslateTextIsEmpty) private var keepPrevResultWhenEmpty @Default(.selectQueryTextWhenWindowActivate) private var selectQueryTextWhenWindowActivate - @Default(.autoPlayAudio) private var autoPlayAudio - + // Auto query @Default(.autoQueryOCRText) private var autoQueryOCRText @Default(.autoQuerySelectedText) private var autoQuerySelectedText @Default(.autoQueryPastedText) private var autoQueryPastedText + @Default(.autoPlayAudio) private var autoPlayAudio + // Auto copy @Default(.autoCopyOCRText) private var autoCopyOCRText @Default(.autoCopySelectedText) private var autoCopySelectedText @Default(.autoCopyFirstTranslatedText) private var autoCopyFirstTranslatedText + // Quick link @Default(.showGoogleQuickLink) private var showGoogleQuickLink @Default(.showEudicQuickLink) private var showEudicQuickLink @Default(.showAppleDictionaryQuickLink) private var showAppleDictionaryQuickLink @Default(.showQuickActionButton) private var showQuickActionButton - @Default(.hideMainWindow) private var hideMainWindow - @Default(.hideMenuBarIcon) private var hideMenuBarIcon - - @Default(.languageDetectOptimize) private var languageDetectOptimize - @Default(.defaultTTSServiceType) private var defaultTTSServiceType - - @Default(.fixedWindowPosition) private var fixedWindowPosition - @Default(.mouseSelectTranslateWindowType) private var mouseSelectTranslateWindowType - @Default(.shortcutSelectTranslateWindowType) private var shortcutSelectTranslateWindowType - @Default(.pinWindowWhenDisplayed) private var pinWindowWhenDisplayed - @Default(.enableBetaFeature) private var enableBetaFeature + // App setting + @EnvironmentObject private var languageState: LanguageState @Default(.appearanceType) private var appearanceType - - @Default(.fontSizeOptionIndex) private var fontSizeOptionIndex + @Default(.hideMenuBarIcon) private var hideMenuBarIcon @Default(.selectedMenuBarIcon) private var selectedMenuBarIcon + @Default(.fontSizeOptionIndex) private var fontSizeOptionIndex @State private var showRefuseAlert = false @State private var showHideMenuBarIconAlert = false @@ -339,14 +298,18 @@ private struct FirstAndSecondLanguageSettingView: View { let oldValue = firstLanguage if newValue == secondLanguage { secondLanguage = oldValue - languageDuplicatedAlert = .init(duplicatedLanguage: newValue, setField: .second, setLanguage: oldValue) + languageDuplicatedAlert = .init( + duplicatedLanguage: newValue, setField: .second, setLanguage: oldValue + ) } } .onChange(of: secondLanguage) { [secondLanguage] newValue in let oldValue = secondLanguage if newValue == firstLanguage { firstLanguage = oldValue - languageDuplicatedAlert = .init(duplicatedLanguage: newValue, setField: .first, setLanguage: oldValue) + languageDuplicatedAlert = .init( + duplicatedLanguage: newValue, setField: .first, setLanguage: oldValue + ) } } .alert( @@ -389,7 +352,8 @@ private struct FirstAndSecondLanguageSettingView: View { // First language should not be same as second language. (\(duplicatedLanguage)) // \(setField) is replaced with \(setLanguage). String( - localized: "setting.general.language.duplicated_alert \(duplicatedLanguage.localizedName)\(String(localized: setField.localizedStringResource))\(setLanguage.localizedName)" + localized: + "setting.general.language.duplicated_alert \(duplicatedLanguage.localizedName)\(String(localized: setField.localizedStringResource))\(setLanguage.localizedName)" ) } } diff --git a/Easydict/objc/Service/Apple/EZAppleService.m b/Easydict/objc/Service/Apple/EZAppleService.m index c4e33eff4..c29ec7d5c 100644 --- a/Easydict/objc/Service/Apple/EZAppleService.m +++ b/Easydict/objc/Service/Apple/EZAppleService.m @@ -16,9 +16,6 @@ #import "EZAppleDictionary.h" #import "Easydict-Swift.h" -@import AppleTranslation; - - static NSString *const kLineBreakText = @"\n"; static NSString *const kParagraphBreakText = @"\n\n"; static NSString *const kIndentationText = @"";