/* 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 "boxes/translate_box.h" #include "boxes/translate_box_content.h" #include "lang/translate_provider.h" #include "core/application.h" #include "core/core_settings.h" #include "core/ui_integration.h" #include "data/data_peer.h" #include "data/data_session.h" #include "history/history.h" #include "lang/lang_instance.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "spellcheck/platform/platform_language.h" #include "ui/boxes/choose_language_box.h" #include "ui/layers/generic_box.h" #include "ui/widgets/multi_select.h" #include "ui/text/text_utilities.h" namespace Ui { namespace { constexpr auto kSkipAtLeastOneDuration = 3 * crl::time(1000); } // namespace void TranslateBox( not_null box, not_null peer, MsgId msgId, TextWithEntities text, bool hasCopyRestriction) { struct State { State(not_null session) : provider(CreateTranslateProvider(session)) { } std::unique_ptr provider; rpl::variable to; }; const auto state = box->lifetime().make_state(&peer->session()); state->to = ChooseTranslateTo(peer->owner().history(peer)); const auto request = std::make_shared( PrepareTranslateProviderRequest( state->provider.get(), peer, msgId, std::move(text))); TranslateBoxContent(box, { .text = request->text, .hasCopyRestriction = hasCopyRestriction, .textContext = Core::TextContext({ .session = &peer->session() }), .to = state->to.value(), .chooseTo = [=] { box->uiShow()->showBox(ChooseTranslateToBox( state->to.current(), crl::guard(box, [=](LanguageId id) { state->to = id; }))); }, .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, }); }); }, }); } bool SkipTranslate(TextWithEntities textWithEntities) { const auto &text = textWithEntities.text; if (text.isEmpty()) { return true; } if (!Core::App().settings().translateButtonEnabled()) { return true; } constexpr auto kFirstChunk = size_t(100); auto hasLetters = (text.size() >= kFirstChunk); for (auto i = 0; i < kFirstChunk; i++) { if (i >= text.size()) { break; } if (text.at(i).isLetter()) { hasLetters = true; break; } } if (!hasLetters) { return true; } #ifndef TDESKTOP_DISABLE_SPELLCHECK const auto result = Platform::Language::Recognize(text); const auto skip = Core::App().settings().skipTranslationLanguages(); return result.known() && ranges::contains(skip, result); #else return false; #endif } object_ptr EditSkipTranslationLanguages() { auto title = tr::lng_translate_settings_choose(); const auto selected = std::make_shared>( Core::App().settings().skipTranslationLanguages()); const auto weak = std::make_shared>(); const auto check = [=](LanguageId id) { const auto already = ranges::contains(*selected, id); if (already) { selected->erase(ranges::remove(*selected, id), selected->end()); } else { selected->push_back(id); } if (already && selected->empty()) { if (const auto strong = weak->get()) { strong->showToast( tr::lng_translate_settings_one(tr::now), kSkipAtLeastOneDuration); } return false; } return true; }; auto result = Box(ChooseLanguageBox, std::move(title), [=]( std::vector &&list) { Core::App().settings().setSkipTranslationLanguages( std::move(list)); Core::App().saveSettingsDelayed(); }, *selected, true, check); *weak = result.data(); return result; } object_ptr ChooseTranslateToBox( LanguageId bringUp, Fn callback) { auto &settings = Core::App().settings(); auto selected = std::vector{ settings.translateTo(), }; for (const auto &id : settings.skipTranslationLanguages()) { if (id != selected.front()) { selected.push_back(id); } } if (bringUp && ranges::contains(selected, bringUp)) { selected.push_back(bringUp); } return Box(ChooseLanguageBox, tr::lng_languages(), [=]( const std::vector &ids) { Expects(!ids.empty()); const auto id = ids.front(); Core::App().settings().setTranslateTo(id); Core::App().saveSettingsDelayed(); callback(id); }, selected, false, nullptr); } LanguageId ChooseTranslateTo(not_null history) { return ChooseTranslateTo(history->translateOfferedFrom()); } LanguageId ChooseTranslateTo(LanguageId offeredFrom) { auto &settings = Core::App().settings(); return ChooseTranslateTo( offeredFrom, settings.translateTo(), settings.skipTranslationLanguages()); } LanguageId ChooseTranslateTo( not_null history, LanguageId savedTo, const std::vector &skip) { return ChooseTranslateTo(history->translateOfferedFrom(), savedTo, skip); } LanguageId ChooseTranslateTo( LanguageId offeredFrom, LanguageId savedTo, const std::vector &skip) { return (offeredFrom != savedTo) ? savedTo : skip.front(); } } // namespace Ui