Add translation API

This commit is contained in:
Ilya Laktyushin 2022-01-28 21:00:56 +03:00
parent b618777883
commit 4c36a2172f
7 changed files with 66 additions and 13 deletions

View File

@ -1046,9 +1046,10 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
})] })]
if canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages) { let (canTranslate, language) = canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages)
if canTranslate {
actions.append(ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuTranslate, accessibilityLabel: strings.Conversation_ContextMenuTranslate), action: { actions.append(ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuTranslate, accessibilityLabel: strings.Conversation_ContextMenuTranslate), action: {
translateText(context: context, text: text) translateText(context: context, text: text, fromLang: language)
})) }))
} }

View File

@ -313,5 +313,9 @@ public extension TelegramEngine {
public func messageReactionList(message: EngineMessage, reaction: String?) -> EngineMessageReactionListContext { public func messageReactionList(message: EngineMessage, reaction: String?) -> EngineMessageReactionListContext {
return EngineMessageReactionListContext(account: self.account, message: message, reaction: reaction) return EngineMessageReactionListContext(account: self.account, message: message, reaction: reaction)
} }
public func translate(text: String, fromLang: String?, toLang: String) -> Signal<String?, NoError> {
return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang)
}
} }
} }

View File

@ -0,0 +1,30 @@
import Foundation
import Postbox
import SwiftSignalKit
import TelegramApi
import MtProtoKit
func _internal_translate(network: Network, text: String, fromLang: String?, toLang: String) -> Signal<String?, NoError> {
var flags: Int32 = 0
flags |= 1
if let _ = fromLang {
flags |= 2
}
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, msgId: nil, text: text, fromLang: fromLang, toLang: toLang))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.TranslatedText?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<String?, NoError> in
guard let result = result else {
return .complete()
}
switch result {
case .translateNoResult:
return .single(nil)
case let .translateResultText(text):
return .single(text)
}
}
}

View File

@ -2920,7 +2920,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .speak: case .speak:
speakText(text.string) speakText(text.string)
case .translate: case .translate:
translateText(context: context, text: text.string) let _ = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|> take(1)
|> deliverOnMainQueue).start(next: { sharedData in
let translationSettings: TranslationSettings
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
translationSettings = current
} else {
translationSettings = TranslationSettings.defaultSettings
}
let (_, language) = canTranslateText(context: context, text: text.string, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages)
translateText(context: context, text: text.string, fromLang: language)
})
} }
}, displayImportedMessageTooltip: { [weak self] _ in }, displayImportedMessageTooltip: { [weak self] _ in
guard let strongSelf = self else { guard let strongSelf = self else {

View File

@ -819,7 +819,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}))) })))
} }
if canTranslateText(context: context, text: messageText, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages) { let (canTranslate, _) = canTranslateText(context: context, text: messageText, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages)
if canTranslate {
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuTranslate, icon: { theme in actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuTranslate, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.actionSheet.primaryTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in }, action: { _, f in

View File

@ -4977,10 +4977,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
})] })]
let (canTranslate, language) = canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages)
if canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages) { if canTranslate {
actions.append(ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuTranslate, accessibilityLabel: presentationData.strings.Conversation_ContextMenuTranslate), action: { actions.append(ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuTranslate, accessibilityLabel: presentationData.strings.Conversation_ContextMenuTranslate), action: {
translateText(context: context, text: text) translateText(context: context, text: text, fromLang: language)
})) }))
} }

View File

@ -3,6 +3,7 @@ import UIKit
import Display import Display
import AccountContext import AccountContext
import NaturalLanguage import NaturalLanguage
import TelegramCore
// Incuding at least one Objective-C class in a swift file ensures that it doesn't get stripped by the linker // Incuding at least one Objective-C class in a swift file ensures that it doesn't get stripped by the linker
private final class LinkHelperClass: NSObject { private final class LinkHelperClass: NSObject {
@ -26,9 +27,9 @@ public var supportedTranslationLanguages = [
@available(iOS 12.0, *) @available(iOS 12.0, *)
private let languageRecognizer = NLLanguageRecognizer() private let languageRecognizer = NLLanguageRecognizer()
public func canTranslateText(context: AccountContext, text: String, showTranslate: Bool, ignoredLanguages: [String]?) -> Bool { public func canTranslateText(context: AccountContext, text: String, showTranslate: Bool, ignoredLanguages: [String]?) -> (canTranslate: Bool, language: String?) {
guard showTranslate, text.count > 0 else { guard showTranslate, text.count > 0 else {
return false return (false, nil)
} }
if #available(iOS 15.0, *) { if #available(iOS 15.0, *) {
@ -46,16 +47,16 @@ public func canTranslateText(context: AccountContext, text: String, showTranslat
let filteredLanguages = hypotheses.filter { supportedTranslationLanguages.contains($0.key.rawValue) }.sorted(by: { $0.value > $1.value }) let filteredLanguages = hypotheses.filter { supportedTranslationLanguages.contains($0.key.rawValue) }.sorted(by: { $0.value > $1.value })
if let language = filteredLanguages.first(where: { supportedTranslationLanguages.contains($0.key.rawValue) }) { if let language = filteredLanguages.first(where: { supportedTranslationLanguages.contains($0.key.rawValue) }) {
return !dontTranslateLanguages.contains(language.key.rawValue) return (!dontTranslateLanguages.contains(language.key.rawValue), language.key.rawValue)
} else { } else {
return false return (false, nil)
} }
} else { } else {
return false return (false, nil)
} }
} }
public func translateText(context: AccountContext, text: String) { public func translateText(context: AccountContext, text: String, fromLang: String? = nil) {
guard !text.isEmpty else { guard !text.isEmpty else {
return return
} }
@ -74,5 +75,8 @@ public func translateText(context: AccountContext, text: String) {
textView.removeFromSuperview() textView.removeFromSuperview()
} }
} }
let toLang = context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode
let _ = context.engine.messages.translate(text: text, fromLang: fromLang, toLang: toLang).start()
} }
} }