diff --git a/.gitmodules b/.gitmodules index b8ed3d659f..2d65da9935 100644 --- a/.gitmodules +++ b/.gitmodules @@ -91,3 +91,6 @@ [submodule "Telegram/ThirdParty/xdg-desktop-portal"] path = Telegram/ThirdParty/xdg-desktop-portal url = https://github.com/flatpak/xdg-desktop-portal.git +[submodule "Telegram/lib_translate"] + path = Telegram/lib_translate + url = https://github.com/desktop-app/lib_translate diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 060290eceb..a1ad8e4912 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(lib_spellcheck) add_subdirectory(lib_storage) add_subdirectory(lib_lottie) add_subdirectory(lib_qr) +add_subdirectory(lib_translate) add_subdirectory(lib_webrtc) add_subdirectory(lib_webview) add_subdirectory(codegen) @@ -35,6 +36,7 @@ include(cmake/td_mtproto.cmake) include(cmake/td_scheme.cmake) include(cmake/td_tde2e.cmake) include(cmake/td_ui.cmake) +include(cmake/telegram_apple_swift_runtime.cmake) include(cmake/generate_appstream_changelog.cmake) if (DESKTOP_APP_TEST_APPS) @@ -78,6 +80,7 @@ PRIVATE desktop-app::lib_storage desktop-app::lib_lottie desktop-app::lib_qr + desktop-app::lib_translate desktop-app::lib_webview desktop-app::lib_ffmpeg desktop-app::lib_stripe @@ -94,6 +97,8 @@ PRIVATE desktop-app::external_xxhash ) +telegram_add_apple_swift_runtime(Telegram) + target_precompile_headers(Telegram PRIVATE $<$:${src_loc}/stdafx.h>) nice_target_sources(Telegram ${src_loc} PRIVATE @@ -1230,6 +1235,8 @@ PRIVATE lang/lang_numbers_animation.h lang/lang_translator.cpp lang/lang_translator.h + lang/translate_mtproto_provider.cpp + lang/translate_mtproto_provider.h lang/translate_provider.cpp lang/translate_provider.h layout/layout_document_generic_preview.cpp @@ -1444,6 +1451,7 @@ PRIVATE platform/linux/overlay_widget_linux.h platform/linux/specific_linux.cpp platform/linux/specific_linux.h + platform/linux/translate_provider_linux.h platform/linux/tray_linux.cpp platform/linux/tray_linux.h platform/linux/webauthn_linux.cpp @@ -1464,8 +1472,10 @@ PRIVATE platform/mac/specific_mac.h platform/mac/specific_mac_p.mm platform/mac/specific_mac_p.h - platform/mac/tray_mac.mm + platform/mac/translate_provider_mac.h + platform/mac/translate_provider_mac.mm platform/mac/tray_mac.h + platform/mac/tray_mac.mm platform/mac/webauthn_mac.mm platform/mac/window_title_mac.mm platform/mac/touchbar/items/mac_formatter_item.h @@ -1499,6 +1509,7 @@ PRIVATE platform/win/overlay_widget_win.h platform/win/specific_win.cpp platform/win/specific_win.h + platform/win/translate_provider_win.h platform/win/tray_win.cpp platform/win/tray_win.h platform/win/webauthn_win.cpp @@ -1519,6 +1530,7 @@ PRIVATE platform/platform_overlay_widget.cpp platform/platform_overlay_widget.h platform/platform_specific.h + platform/platform_translate_provider.h platform/platform_tray.h platform/platform_webauthn.h platform/platform_window_title.h diff --git a/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp b/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp new file mode 100644 index 0000000000..eab649f289 --- /dev/null +++ b/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp @@ -0,0 +1,82 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "lang/translate_mtproto_provider.h" + +#include "api/api_text_entities.h" +#include "data/data_peer.h" +#include "main/main_session.h" +#include "mtproto/sender.h" + +namespace Ui { +namespace { + +class MTProtoTranslateProvider final : public TranslateProvider { +public: + explicit MTProtoTranslateProvider(not_null session) + : _api(&session->mtp()) { + } + + [[nodiscard]] bool supportsMessageId() const override { + return true; + } + + void request( + TranslateProviderRequest request, + LanguageId to, + Fn)> done) override { + using Flag = MTPmessages_TranslateText::Flag; + const auto flags = request.msgId + ? (Flag::f_peer | Flag::f_id) + : !request.text.text.isEmpty() + ? Flag::f_text + : Flag(0); + if (!flags) { + done(std::nullopt); + return; + } + _api.request(MTPmessages_TranslateText( + MTP_flags(flags), + request.msgId ? request.peer->input() : MTP_inputPeerEmpty(), + (request.msgId + ? MTP_vector(1, MTP_int(request.msgId)) + : MTPVector()), + (request.msgId + ? MTPVector() + : MTP_vector(1, MTP_textWithEntities( + MTP_string(request.text.text), + Api::EntitiesToMTP( + &request.peer->session(), + request.text.entities, + Api::ConvertOption::SkipLocal)))), + MTP_string(to.twoLetterCode()) + )).done([=](const MTPmessages_TranslatedText &result) { + const auto &data = result.data(); + const auto &list = data.vresult().v; + done(list.isEmpty() + ? std::optional() + : std::optional(Api::ParseTextWithEntities( + &request.peer->session(), + list.front()))); + }).fail([=](const MTP::Error &) { + done(std::nullopt); + }).send(); + } + +private: + MTP::Sender _api; + +}; + +} // namespace + +std::unique_ptr CreateMTProtoTranslateProvider( + not_null session) { + return std::make_unique(session); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/lang/translate_mtproto_provider.h b/Telegram/SourceFiles/lang/translate_mtproto_provider.h new file mode 100644 index 0000000000..9121450ecc --- /dev/null +++ b/Telegram/SourceFiles/lang/translate_mtproto_provider.h @@ -0,0 +1,21 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "translate_provider.h" + +namespace Main { +class Session; +} // namespace Main + +namespace Ui { + +[[nodiscard]] std::unique_ptr CreateMTProtoTranslateProvider( + not_null session); + +} // namespace Ui diff --git a/Telegram/SourceFiles/lang/translate_provider.cpp b/Telegram/SourceFiles/lang/translate_provider.cpp index e56ea74184..ef318a3702 100644 --- a/Telegram/SourceFiles/lang/translate_provider.cpp +++ b/Telegram/SourceFiles/lang/translate_provider.cpp @@ -7,93 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "lang/translate_provider.h" -#include "api/api_text_entities.h" #include "data/data_msg_id.h" #include "data/data_peer.h" #include "data/data_session.h" #include "history/history_item.h" -#include "main/main_session.h" -#include "mtproto/sender.h" +#include "lang/translate_mtproto_provider.h" +#include "platform/platform_translate_provider.h" namespace Ui { -namespace { - -enum class TranslateProviderKind { - MTProtoServer, -}; - -[[nodiscard]] TranslateProviderKind CurrentTranslateProviderKind() { - return TranslateProviderKind::MTProtoServer; -} - -class MTProtoTranslateProvider final : public TranslateProvider { -public: - explicit MTProtoTranslateProvider(not_null session) - : _api(&session->mtp()) { - } - - [[nodiscard]] bool supportsMessageId() const override { - return true; - } - - void request( - TranslateProviderRequest request, - LanguageId to, - Fn)> done) override { - using Flag = MTPmessages_TranslateText::Flag; - const auto flags = request.msgId - ? (Flag::f_peer | Flag::f_id) - : !request.text.text.isEmpty() - ? Flag::f_text - : Flag(0); - if (!flags) { - done(std::nullopt); - return; - } - const auto callback = std::make_shared< - Fn)>>(std::move(done)); - _api.request(MTPmessages_TranslateText( - MTP_flags(flags), - request.msgId ? request.peer->input() : MTP_inputPeerEmpty(), - (request.msgId - ? MTP_vector(1, MTP_int(request.msgId)) - : MTPVector()), - (request.msgId - ? MTPVector() - : MTP_vector(1, MTP_textWithEntities( - MTP_string(request.text.text), - Api::EntitiesToMTP( - &request.peer->session(), - request.text.entities, - Api::ConvertOption::SkipLocal)))), - MTP_string(to.twoLetterCode()) - )).done([=](const MTPmessages_TranslatedText &result) { - const auto &data = result.data(); - const auto &list = data.vresult().v; - (*callback)(list.isEmpty() - ? std::optional() - : std::optional(Api::ParseTextWithEntities( - &request.peer->session(), - list.front()))); - }).fail([=](const MTP::Error &) { - (*callback)(std::nullopt); - }).send(); - } - -private: - MTP::Sender _api; - -}; - -} // namespace std::unique_ptr CreateTranslateProvider( not_null session) { - switch (CurrentTranslateProviderKind()) { - case TranslateProviderKind::MTProtoServer: - return std::make_unique(session); - } - return std::make_unique(session); + return CreateMTProtoTranslateProvider(session); } TranslateProviderRequest PrepareTranslateProviderRequest( diff --git a/Telegram/SourceFiles/lang/translate_provider.h b/Telegram/SourceFiles/lang/translate_provider.h index 8da0ca0950..2902207656 100644 --- a/Telegram/SourceFiles/lang/translate_provider.h +++ b/Telegram/SourceFiles/lang/translate_provider.h @@ -7,10 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "spellcheck/platform/platform_language.h" -#include "ui/text/text_entity.h" - -class PeerData; +#include namespace Main { class Session; @@ -18,22 +15,6 @@ class Session; namespace Ui { -struct TranslateProviderRequest { - not_null peer; - MsgId msgId = 0; - TextWithEntities text; -}; - -class TranslateProvider { -public: - virtual ~TranslateProvider() = default; - [[nodiscard]] virtual bool supportsMessageId() const = 0; - virtual void request( - TranslateProviderRequest request, - LanguageId to, - Fn)> done) = 0; -}; - [[nodiscard]] std::unique_ptr CreateTranslateProvider( not_null session); diff --git a/Telegram/SourceFiles/platform/linux/translate_provider_linux.h b/Telegram/SourceFiles/platform/linux/translate_provider_linux.h new file mode 100644 index 0000000000..8fed093cb4 --- /dev/null +++ b/Telegram/SourceFiles/platform/linux/translate_provider_linux.h @@ -0,0 +1,22 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "platform/platform_translate_provider.h" + +namespace Platform { + +inline bool IsTranslateProviderAvailable() { + return false; +} + +inline std::unique_ptr CreateTranslateProvider() { + return nullptr; +} + +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/translate_provider_mac.h b/Telegram/SourceFiles/platform/mac/translate_provider_mac.h new file mode 100644 index 0000000000..996f5d484f --- /dev/null +++ b/Telegram/SourceFiles/platform/mac/translate_provider_mac.h @@ -0,0 +1,18 @@ +// This file is part of Telegram Desktop, +// the official desktop application for the Telegram messaging service. +// +// For license and copyright information please follow this link: +// https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +// +#pragma once + +#include "translate_provider.h" + +namespace Platform { + +[[nodiscard]] std::unique_ptr +CreateTranslateProvider(); + +[[nodiscard]] bool IsTranslateProviderAvailable(); + +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm b/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm new file mode 100644 index 0000000000..d5717d2e03 --- /dev/null +++ b/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm @@ -0,0 +1,98 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "platform/mac/translate_provider_mac.h" + +#include "base/weak_ptr.h" +#include "translate_provider_mac_swift_bridge.h" + +#include +#include +#include + +namespace Platform { +namespace { + +class TranslateProvider final : public Ui::TranslateProvider +, public base::has_weak_ptr { +public: + [[nodiscard]] bool supportsMessageId() const override { + return false; + } + + void request( + Ui::TranslateProviderRequest request, + LanguageId to, + Fn)> done) override { + if (request.text.text.isEmpty()) { + done(std::nullopt); + return; + } + const auto text = request.text.text.toUtf8(); + const auto target = to.twoLetterCode().toUtf8(); + if (target.isEmpty()) { + done(std::nullopt); + return; + } + struct CallbackContext { + base::weak_ptr provider; + Fn)> done; + }; + auto ownedContext = std::make_unique(CallbackContext{ + .provider = base::make_weak(this), + .done = std::move(done), + }); + TranslateProviderMacSwiftTranslate( + text.constData(), + target.constData(), + ownedContext.release(), + [](void *context, const char *resultUtf8, const char *errorUtf8) { + auto guard = std::unique_ptr( + static_cast(context)); + auto done = std::move(guard->done); + const auto isAlive = (guard->provider.get() != nullptr); + auto translatedText = QString(); + auto hasError = (resultUtf8 == nullptr); + if (resultUtf8 != nullptr) { + translatedText = QString::fromUtf8(resultUtf8); + std::free(const_cast(resultUtf8)); + } + if (errorUtf8 != nullptr) { + hasError = true; + std::free(const_cast(errorUtf8)); + } + if (!isAlive) { + return; + } + crl::on_main([=, + done = std::move(done), + translatedText = std::move(translatedText)] { + done(hasError + ? std::optional() + : std::optional(TextWithEntities{ + .text = std::move(translatedText), + })); + }); + }); + } + +}; + +} // namespace + +std::unique_ptr CreateTranslateProvider() { + if (TranslateProviderMacSwiftIsAvailable()) { + return std::make_unique(); + } + return nullptr; +} + +bool IsTranslateProviderAvailable() { + return TranslateProviderMacSwiftIsAvailable(); +} + +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/platform_translate_provider.h b/Telegram/SourceFiles/platform/platform_translate_provider.h new file mode 100644 index 0000000000..a15b7a8e5c --- /dev/null +++ b/Telegram/SourceFiles/platform/platform_translate_provider.h @@ -0,0 +1,25 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "translate_provider.h" + +namespace Platform { + +[[nodiscard]] bool IsTranslateProviderAvailable(); +[[nodiscard]] std::unique_ptr CreateTranslateProvider(); + +} // namespace Platform + +#if defined Q_OS_WINRT || defined Q_OS_WIN +#include "platform/win/translate_provider_win.h" +#elif defined Q_OS_MAC +#include "platform/mac/translate_provider_mac.h" +#else +#include "platform/linux/translate_provider_linux.h" +#endif diff --git a/Telegram/SourceFiles/platform/win/translate_provider_win.h b/Telegram/SourceFiles/platform/win/translate_provider_win.h new file mode 100644 index 0000000000..8fed093cb4 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/translate_provider_win.h @@ -0,0 +1,22 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "platform/platform_translate_provider.h" + +namespace Platform { + +inline bool IsTranslateProviderAvailable() { + return false; +} + +inline std::unique_ptr CreateTranslateProvider() { + return nullptr; +} + +} // namespace Platform diff --git a/Telegram/cmake/telegram_apple_swift_runtime.cmake b/Telegram/cmake/telegram_apple_swift_runtime.cmake new file mode 100644 index 0000000000..36125c26f9 --- /dev/null +++ b/Telegram/cmake/telegram_apple_swift_runtime.cmake @@ -0,0 +1,27 @@ +# This file is part of Telegram Desktop, +# the official desktop application for the Telegram messaging service. +# +# For license and copyright information please follow this link: +# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL + +function(telegram_add_apple_swift_runtime target_name) + if (NOT APPLE) + return() + endif() + + target_link_options(${target_name} + PRIVATE + "-Wl,-rpath,/usr/lib/swift" + "-Wl,-rpath,@executable_path/../Frameworks" + ) + + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND mkdir -p $/../Frameworks + COMMAND xcrun swift-stdlib-tool + --copy + --platform macosx + --scan-executable $ + --destination $/../Frameworks + VERBATIM + ) +endfunction() diff --git a/Telegram/lib_translate b/Telegram/lib_translate new file mode 160000 index 0000000000..48d9e3ca92 --- /dev/null +++ b/Telegram/lib_translate @@ -0,0 +1 @@ +Subproject commit 48d9e3ca92fbee00d636ace5a2c71f9972b5ac27