Added platform provider of translations.

This commit is contained in:
23rd
2026-03-02 16:56:43 +03:00
parent cec580a645
commit d7e8199365
13 changed files with 336 additions and 99 deletions
+3
View File
@@ -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
+13 -1
View File
@@ -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 $<$<COMPILE_LANGUAGE:CXX,OBJCXX>:${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
@@ -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<Main::Session*> session)
: _api(&session->mtp()) {
}
[[nodiscard]] bool supportsMessageId() const override {
return true;
}
void request(
TranslateProviderRequest request,
LanguageId to,
Fn<void(std::optional<TextWithEntities>)> 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<MTPint>(1, MTP_int(request.msgId))
: MTPVector<MTPint>()),
(request.msgId
? MTPVector<MTPTextWithEntities>()
: MTP_vector<MTPTextWithEntities>(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<TextWithEntities>()
: std::optional<TextWithEntities>(Api::ParseTextWithEntities(
&request.peer->session(),
list.front())));
}).fail([=](const MTP::Error &) {
done(std::nullopt);
}).send();
}
private:
MTP::Sender _api;
};
} // namespace
std::unique_ptr<TranslateProvider> CreateMTProtoTranslateProvider(
not_null<Main::Session*> session) {
return std::make_unique<MTProtoTranslateProvider>(session);
}
} // namespace Ui
@@ -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<TranslateProvider> CreateMTProtoTranslateProvider(
not_null<Main::Session*> session);
} // namespace Ui
@@ -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<Main::Session*> session)
: _api(&session->mtp()) {
}
[[nodiscard]] bool supportsMessageId() const override {
return true;
}
void request(
TranslateProviderRequest request,
LanguageId to,
Fn<void(std::optional<TextWithEntities>)> 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<void(std::optional<TextWithEntities>)>>(std::move(done));
_api.request(MTPmessages_TranslateText(
MTP_flags(flags),
request.msgId ? request.peer->input() : MTP_inputPeerEmpty(),
(request.msgId
? MTP_vector<MTPint>(1, MTP_int(request.msgId))
: MTPVector<MTPint>()),
(request.msgId
? MTPVector<MTPTextWithEntities>()
: MTP_vector<MTPTextWithEntities>(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<TextWithEntities>()
: std::optional<TextWithEntities>(Api::ParseTextWithEntities(
&request.peer->session(),
list.front())));
}).fail([=](const MTP::Error &) {
(*callback)(std::nullopt);
}).send();
}
private:
MTP::Sender _api;
};
} // namespace
std::unique_ptr<TranslateProvider> CreateTranslateProvider(
not_null<Main::Session*> session) {
switch (CurrentTranslateProviderKind()) {
case TranslateProviderKind::MTProtoServer:
return std::make_unique<MTProtoTranslateProvider>(session);
}
return std::make_unique<MTProtoTranslateProvider>(session);
return CreateMTProtoTranslateProvider(session);
}
TranslateProviderRequest PrepareTranslateProviderRequest(
+1 -20
View File
@@ -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 <translate_provider.h>
namespace Main {
class Session;
@@ -18,22 +15,6 @@ class Session;
namespace Ui {
struct TranslateProviderRequest {
not_null<PeerData*> 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<void(std::optional<TextWithEntities>)> done) = 0;
};
[[nodiscard]] std::unique_ptr<TranslateProvider> CreateTranslateProvider(
not_null<Main::Session*> session);
@@ -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<Ui::TranslateProvider> CreateTranslateProvider() {
return nullptr;
}
} // namespace Platform
@@ -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<Ui::TranslateProvider>
CreateTranslateProvider();
[[nodiscard]] bool IsTranslateProviderAvailable();
} // namespace Platform
@@ -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 <cstdlib>
#include <memory>
#include <optional>
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<void(std::optional<TextWithEntities>)> 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<TranslateProvider> provider;
Fn<void(std::optional<TextWithEntities>)> done;
};
auto ownedContext = std::make_unique<CallbackContext>(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<CallbackContext>(
static_cast<CallbackContext*>(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<char*>(resultUtf8));
}
if (errorUtf8 != nullptr) {
hasError = true;
std::free(const_cast<char*>(errorUtf8));
}
if (!isAlive) {
return;
}
crl::on_main([=,
done = std::move(done),
translatedText = std::move(translatedText)] {
done(hasError
? std::optional<TextWithEntities>()
: std::optional<TextWithEntities>(TextWithEntities{
.text = std::move(translatedText),
}));
});
});
}
};
} // namespace
std::unique_ptr<Ui::TranslateProvider> CreateTranslateProvider() {
if (TranslateProviderMacSwiftIsAvailable()) {
return std::make_unique<TranslateProvider>();
}
return nullptr;
}
bool IsTranslateProviderAvailable() {
return TranslateProviderMacSwiftIsAvailable();
}
} // namespace Platform
@@ -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<Ui::TranslateProvider> 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
@@ -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<Ui::TranslateProvider> CreateTranslateProvider() {
return nullptr;
}
} // namespace Platform
@@ -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 $<TARGET_FILE_DIR:${target_name}>/../Frameworks
COMMAND xcrun swift-stdlib-tool
--copy
--platform macosx
--scan-executable $<TARGET_FILE:${target_name}>
--destination $<TARGET_FILE_DIR:${target_name}>/../Frameworks
VERBATIM
)
endfunction()