diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index cdef1a3b23..931ea862bd 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -6774,6 +6774,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_language_not_ready_link" = "translation platform"; "lng_translate_box_error" = "Translate failed."; +"lng_translate_box_error_language_pack_not_installed" = "Translation requires a local language pack. Download it in System Settings."; "lng_translate_settings_subtitle" = "Translate Messages"; "lng_translate_settings_show" = "Show Translate Button"; diff --git a/Telegram/SourceFiles/boxes/translate_box.cpp b/Telegram/SourceFiles/boxes/translate_box.cpp index d07a87f74a..e91a5f4956 100644 --- a/Telegram/SourceFiles/boxes/translate_box.cpp +++ b/Telegram/SourceFiles/boxes/translate_box.cpp @@ -64,8 +64,25 @@ void TranslateBox( state->to.current(), crl::guard(box, [=](LanguageId id) { state->to = id; }))); }, - .request = [=](LanguageId to, Fn)> done) { - state->provider->request(*request, to, std::move(done)); + .request = [=]( + LanguageId to, + Fn done) { + state->provider->request( + *request, + to, + [done = std::move(done)](TranslateProviderResult result) { + using ProviderError = TranslateProviderError; + using UiError = TranslateBoxContentError; + done(TranslateBoxContentResult{ + .text = std::move(result.text), + .error = (result.error + == ProviderError::LocalLanguagePackMissing) + ? UiError::LocalLanguagePackMissing + : (result.error == ProviderError::None) + ? UiError::None + : UiError::Unknown, + }); + }); }, }); } diff --git a/Telegram/SourceFiles/boxes/translate_box_content.cpp b/Telegram/SourceFiles/boxes/translate_box_content.cpp index c467ad759c..daf204eee3 100644 --- a/Telegram/SourceFiles/boxes/translate_box_content.cpp +++ b/Telegram/SourceFiles/boxes/translate_box_content.cpp @@ -86,7 +86,7 @@ void TranslateBoxContent( const auto textContext = std::move(args.textContext); const auto chooseTo = std::make_shared>(std::move(args.chooseTo)); const auto request = std::make_shared< - Fn)>)>>( + Fn)>>( std::move(args.request)); auto to = std::move(args.to) | rpl::start_spawning(box->lifetime()); @@ -181,9 +181,12 @@ void TranslateBoxContent( }; const auto state = box->lifetime().make_state(); - const auto showText = [=](std::optional translatedText) { - auto value = translatedText.value_or( - tr::italic(tr::lng_translate_box_error(tr::now))); + const auto showText = [=](TranslateBoxContentResult result) { + using UiError = TranslateBoxContentError; + auto value = result.text.value_or( + tr::italic(((result.error == UiError::LocalLanguagePackMissing) + ? tr::lng_translate_box_error_language_pack_not_installed + : tr::lng_translate_box_error)(tr::now))); translated->entity()->setMarkedText(value, textContext); translated->show(anim::type::instant); loading->hide(anim::type::instant); @@ -192,11 +195,11 @@ void TranslateBoxContent( const auto requestId = ++state->requestId; loading->show(anim::type::instant); translated->hide(anim::type::instant); - (*request)(id, [=](std::optional translatedText) { + (*request)(id, [=](TranslateBoxContentResult result) { if (state->requestId != requestId) { return; } - showText(std::move(translatedText)); + showText(std::move(result)); }); }; std::move(to) | rpl::on_next(send, box->lifetime()); diff --git a/Telegram/SourceFiles/boxes/translate_box_content.h b/Telegram/SourceFiles/boxes/translate_box_content.h index e2d982bd8b..38e68804b7 100644 --- a/Telegram/SourceFiles/boxes/translate_box_content.h +++ b/Telegram/SourceFiles/boxes/translate_box_content.h @@ -15,6 +15,17 @@ struct MarkedContext; namespace Ui { +enum class TranslateBoxContentError { + None = 0, + Unknown, + LocalLanguagePackMissing, +}; + +struct TranslateBoxContentResult { + std::optional text; + TranslateBoxContentError error = TranslateBoxContentError::None; +}; + class GenericBox; struct TranslateBoxContentArgs { @@ -23,7 +34,7 @@ struct TranslateBoxContentArgs { Text::MarkedContext textContext; rpl::producer to; Fn chooseTo; - Fn)>)> request; + Fn)> request; }; void TranslateBoxContent( diff --git a/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp b/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp index eab649f289..1c487411df 100644 --- a/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp +++ b/Telegram/SourceFiles/lang/translate_mtproto_provider.cpp @@ -28,7 +28,7 @@ public: void request( TranslateProviderRequest request, LanguageId to, - Fn)> done) override { + Fn done) override { using Flag = MTPmessages_TranslateText::Flag; const auto flags = request.msgId ? (Flag::f_peer | Flag::f_id) @@ -36,7 +36,9 @@ public: ? Flag::f_text : Flag(0); if (!flags) { - done(std::nullopt); + done(TranslateProviderResult{ + .error = TranslateProviderError::Unknown, + }); return; } _api.request(MTPmessages_TranslateText( @@ -58,12 +60,18 @@ public: 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()))); + ? TranslateProviderResult{ + .error = TranslateProviderError::Unknown, + } + : TranslateProviderResult{ + .text = Api::ParseTextWithEntities( + &request.peer->session(), + list.front()), + }); }).fail([=](const MTP::Error &) { - done(std::nullopt); + done(TranslateProviderResult{ + .error = TranslateProviderError::Unknown, + }); }).send(); } diff --git a/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm b/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm index d5717d2e03..7e9f7f779a 100644 --- a/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm +++ b/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm @@ -17,6 +17,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Platform { namespace { +[[nodiscard]] Ui::TranslateProviderError ParseErrorCode( + const char *errorUtf8) { + return !std::strcmp(errorUtf8, "local-language-pack-missing") + ? Ui::TranslateProviderError::LocalLanguagePackMissing + : Ui::TranslateProviderError::Unknown; +} + class TranslateProvider final : public Ui::TranslateProvider , public base::has_weak_ptr { public: @@ -27,20 +34,24 @@ public: void request( Ui::TranslateProviderRequest request, LanguageId to, - Fn)> done) override { + Fn done) override { if (request.text.text.isEmpty()) { - done(std::nullopt); + done(Ui::TranslateProviderResult{ + .error = Ui::TranslateProviderError::Unknown, + }); return; } const auto text = request.text.text.toUtf8(); const auto target = to.twoLetterCode().toUtf8(); if (target.isEmpty()) { - done(std::nullopt); + done(Ui::TranslateProviderResult{ + .error = Ui::TranslateProviderError::Unknown, + }); return; } struct CallbackContext { base::weak_ptr provider; - Fn)> done; + Fn done; }; auto ownedContext = std::make_unique(CallbackContext{ .provider = base::make_weak(this), @@ -55,27 +66,26 @@ public: static_cast(context)); auto done = std::move(guard->done); const auto isAlive = (guard->provider.get() != nullptr); - auto translatedText = QString(); - auto hasError = (resultUtf8 == nullptr); + auto result = Ui::TranslateProviderResult(); if (resultUtf8 != nullptr) { - translatedText = QString::fromUtf8(resultUtf8); + result.text = TextWithEntities{ + .text = QString::fromUtf8(resultUtf8), + }; std::free(const_cast(resultUtf8)); } if (errorUtf8 != nullptr) { - hasError = true; + result.error = ParseErrorCode(errorUtf8); std::free(const_cast(errorUtf8)); + } else if (!result.text.has_value()) { + result.error = Ui::TranslateProviderError::Unknown; } 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), - })); + result = std::move(result)] { + done(std::move(result)); }); }); } diff --git a/Telegram/lib_translate b/Telegram/lib_translate index 48d9e3ca92..ed5bbec209 160000 --- a/Telegram/lib_translate +++ b/Telegram/lib_translate @@ -1 +1 @@ -Subproject commit 48d9e3ca92fbee00d636ace5a2c71f9972b5ac27 +Subproject commit ed5bbec209451bd56237783e783fdadfb3c1fdd2