Don't offer translate from / to the same language.

This commit is contained in:
John Preston 2023-02-07 16:29:34 +04:00
parent d889cd0e72
commit 64f4e0dd52
10 changed files with 259 additions and 41 deletions

View file

@ -35,7 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"cloud_lng_passport_in_it" = "Italian";
"cloud_lng_passport_in_ja" = "Japanese";
"cloud_lng_passport_in_ka" = "Georgian";
"cloud_lng_passport_in_km" = "Khmer";
// "cloud_lng_passport_in_km" = "Khmer";
"cloud_lng_passport_in_ko" = "Korean";
"cloud_lng_passport_in_lo" = "Lao";
"cloud_lng_passport_in_lt" = "Lithuanian";
@ -58,3 +58,99 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"cloud_lng_passport_in_uk" = "Ukrainian";
"cloud_lng_passport_in_uz" = "Uzbek";
"cloud_lng_passport_in_vi" = "Vietnamese";
"cloud_lng_translate_to_ar" = "Arabic";
"cloud_lng_translate_to_az" = "Azerbaijani";
"cloud_lng_translate_to_bg" = "Bulgarian";
// "cloud_lng_translate_to_bn" = "Bangla";
"cloud_lng_translate_to_cs" = "Czech";
"cloud_lng_translate_to_da" = "Danish";
"cloud_lng_translate_to_de" = "German";
// "cloud_lng_translate_to_dv" = "Divehi";
// "cloud_lng_translate_to_dz" = "Dzongkha";
"cloud_lng_translate_to_el" = "Greek";
"cloud_lng_translate_to_en" = "English";
"cloud_lng_translate_to_es" = "Spanish";
"cloud_lng_translate_to_et" = "Estonian";
"cloud_lng_translate_to_fa" = "Persian";
"cloud_lng_translate_to_fr" = "French";
"cloud_lng_translate_to_he" = "Hebrew";
"cloud_lng_translate_to_hr" = "Croatian";
"cloud_lng_translate_to_hu" = "Hungarian";
"cloud_lng_translate_to_hy" = "Armenian";
"cloud_lng_translate_to_id" = "Indonesian";
"cloud_lng_translate_to_is" = "Icelandic";
"cloud_lng_translate_to_it" = "Italian";
"cloud_lng_translate_to_ja" = "Japanese";
"cloud_lng_translate_to_ka" = "Georgian";
// "cloud_lng_translate_to_km" = "Khmer";
"cloud_lng_translate_to_ko" = "Korean";
"cloud_lng_translate_to_lo" = "Lao";
"cloud_lng_translate_to_lt" = "Lithuanian";
"cloud_lng_translate_to_lv" = "Latvian";
"cloud_lng_translate_to_mk" = "Macedonian";
"cloud_lng_translate_to_mn" = "Mongolian";
"cloud_lng_translate_to_ms" = "Malay";
"cloud_lng_translate_to_my" = "Burmese";
"cloud_lng_translate_to_ne" = "Nepali";
"cloud_lng_translate_to_nl" = "Dutch";
"cloud_lng_translate_to_pl" = "Polish";
"cloud_lng_translate_to_pt" = "Portuguese";
"cloud_lng_translate_to_ro" = "Romanian";
"cloud_lng_translate_to_ru" = "Russian";
"cloud_lng_translate_to_sk" = "Slovak";
"cloud_lng_translate_to_sl" = "Slovenian";
"cloud_lng_translate_to_th" = "Thai";
"cloud_lng_translate_to_tk" = "Turkmen";
"cloud_lng_translate_to_tr" = "Turkish";
"cloud_lng_translate_to_uk" = "Ukrainian";
"cloud_lng_translate_to_uz" = "Uzbek";
"cloud_lng_translate_to_vi" = "Vietnamese";
"cloud_lng_language_ar" = "Arabic";
"cloud_lng_language_az" = "Azerbaijani";
"cloud_lng_language_bg" = "Bulgarian";
// "cloud_lng_language_bn" = "Bangla";
"cloud_lng_language_cs" = "Czech";
"cloud_lng_language_da" = "Danish";
"cloud_lng_language_de" = "German";
// "cloud_lng_language_dv" = "Divehi";
// "cloud_lng_language_dz" = "Dzongkha";
"cloud_lng_language_el" = "Greek";
"cloud_lng_language_en" = "English";
"cloud_lng_language_es" = "Spanish";
"cloud_lng_language_et" = "Estonian";
"cloud_lng_language_fa" = "Persian";
"cloud_lng_language_fr" = "French";
"cloud_lng_language_he" = "Hebrew";
"cloud_lng_language_hr" = "Croatian";
"cloud_lng_language_hu" = "Hungarian";
"cloud_lng_language_hy" = "Armenian";
"cloud_lng_language_id" = "Indonesian";
"cloud_lng_language_is" = "Icelandic";
"cloud_lng_language_it" = "Italian";
"cloud_lng_language_ja" = "Japanese";
"cloud_lng_language_ka" = "Georgian";
// "cloud_lng_language_km" = "Khmer";
"cloud_lng_language_ko" = "Korean";
"cloud_lng_language_lo" = "Lao";
"cloud_lng_language_lt" = "Lithuanian";
"cloud_lng_language_lv" = "Latvian";
"cloud_lng_language_mk" = "Macedonian";
"cloud_lng_language_mn" = "Mongolian";
"cloud_lng_language_ms" = "Malay";
"cloud_lng_language_my" = "Burmese";
"cloud_lng_language_ne" = "Nepali";
"cloud_lng_language_nl" = "Dutch";
"cloud_lng_language_pl" = "Polish";
"cloud_lng_language_pt" = "Portuguese";
"cloud_lng_language_ro" = "Romanian";
"cloud_lng_language_ru" = "Russian";
"cloud_lng_language_sk" = "Slovak";
"cloud_lng_language_sl" = "Slovenian";
"cloud_lng_language_th" = "Thai";
"cloud_lng_language_tk" = "Turkmen";
"cloud_lng_language_tr" = "Turkish";
"cloud_lng_language_uk" = "Ukrainian";
"cloud_lng_language_uz" = "Uzbek";
"cloud_lng_language_vi" = "Vietnamese";

View file

@ -2233,8 +2233,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_translate_show_original" = "Show Original";
"lng_translate_bar_to" = "Translate to {name}";
"lng_translate_bar_to_other" = "Translate to {name}";
"lng_translate_menu_to" = "Translate To";
"lng_translate_menu_dont" = "Don't translate {name}";
"lng_translate_menu_dont_other" = "Don't translate {name}";
"lng_translate_menu_hide" = "Hide";
"lng_translate_hidden_user" = "Translation bar is now hidden for this chat.";
"lng_translate_hidden_group" = "Translation bar is now hidden for this group.";
@ -3389,6 +3391,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_translate_settings_chat" = "Translate Entire Chat";
"lng_translate_settings_choose" = "Do Not Translate";
"lng_translate_settings_about" = "The 'Translate' button will appear when you open a context menu on a text message.";
"lng_translate_settings_one" = "Please choose at least one language so that it can be used as the \"Translate to\" language.";
"lng_launch_exe_warning" = "This file has a {extension} extension.\nAre you sure you want to run it?";
"lng_launch_svg_warning" = "Opening this file can potentially expose your IP address to its sender. Continue?";

View file

@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#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"
@ -96,9 +98,15 @@ void TranslateBox(
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
const auto container = box->verticalLayout();
auto id = Core::App().settings().translateToValue();
const auto api = box->lifetime().make_state<MTP::Sender>(
&peer->session().mtp());
struct State {
State(not_null<Main::Session*> session) : api(&session->mtp()) {
}
MTP::Sender api;
rpl::variable<LanguageId> to;
};
const auto state = box->lifetime().make_state<State>(&peer->session());
state->to = ChooseTranslateTo(peer->owner().history(peer));
text.entities = ranges::views::all(
text.entities
@ -174,10 +182,10 @@ void TranslateBox(
const auto padding = st::settingsSubsectionTitlePadding;
const auto subtitle = Settings::AddSubsectionTitle(
container,
rpl::duplicate(id) | rpl::map(LanguageName));
state->to.value() | rpl::map(LanguageName));
// Workaround.
rpl::duplicate(id) | rpl::start_with_next([=] {
state->to.value() | rpl::start_with_next([=] {
subtitle->resizeToWidth(container->width()
- padding.left()
- padding.right());
@ -197,7 +205,7 @@ void TranslateBox(
box,
st::aboutLabel,
std::min(original->entity()->height() / lineHeight, kMaxLines),
rpl::duplicate(id) | rpl::map([=](LanguageId id) {
state->to.value() | rpl::map([=](LanguageId id) {
return id.locale().textDirection() == Qt::RightToLeft;
}))));
@ -210,7 +218,7 @@ void TranslateBox(
const auto send = [=](LanguageId to) {
loading->show(anim::type::instant);
translated->hide(anim::type::instant);
api->request(MTPmessages_TranslateText(
state->api.request(MTPmessages_TranslateText(
MTP_flags(flags),
msgId ? peer->input : MTP_inputPeerEmpty(),
(msgId
@ -221,7 +229,7 @@ void TranslateBox(
: MTP_vector<MTPTextWithEntities>(1, MTP_textWithEntities(
MTP_string(text.text),
MTP_vector<MTPMessageEntity>()))),
MTP_string(to.locale().name().mid(0, 2))
MTP_string(to.twoLetterCode())
)).done([=](const MTPmessages_TranslatedText &result) {
const auto &data = result.data();
const auto &list = data.vresult().v;
@ -232,13 +240,15 @@ void TranslateBox(
showText(tr::lng_translate_box_error(tr::now));
}).send();
};
std::move(id) | rpl::start_with_next(send, box->lifetime());
state->to.value() | rpl::start_with_next(send, box->lifetime());
box->addLeftButton(tr::lng_settings_language(), [=] {
if (loading->toggled()) {
return;
}
Ui::BoxShow(box).showBox(ChooseTranslateToBox());
Ui::BoxShow(box).showBox(ChooseTranslateToBox(
state->to.current(),
crl::guard(box, [=](LanguageId id) { state->to = id; })));
});
}
@ -283,17 +293,50 @@ object_ptr<BoxContent> EditSkipTranslationLanguages() {
}, Core::App().settings().skipTranslationLanguages(), true);
}
object_ptr<BoxContent> ChooseTranslateToBox() {
const auto selected = std::vector<LanguageId>{
object_ptr<BoxContent> ChooseTranslateToBox(
LanguageId bringUp,
Fn<void(LanguageId)> callback) {
auto selected = std::vector<LanguageId>{
Core::App().settings().translateTo(),
};
if (bringUp && bringUp != selected.front()) {
selected.push_back(bringUp);
}
return Box(ChooseLanguageBox, tr::lng_languages(), [=](
const std::vector<LanguageId> &ids) {
Expects(!ids.empty());
Core::App().settings().setTranslateTo(ids.front());
const auto id = ids.front();
Core::App().settings().setTranslateTo(id);
Core::App().saveSettingsDelayed();
callback(id);
}, selected, false);
}
LanguageId ChooseTranslateTo(not_null<History*> 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*> history,
LanguageId savedTo,
const std::vector<LanguageId> &skip) {
return ChooseTranslateTo(history->translateOfferedFrom(), savedTo, skip);
}
LanguageId ChooseTranslateTo(
LanguageId offeredFrom,
LanguageId savedTo,
const std::vector<LanguageId> &skip) {
return (offeredFrom != savedTo) ? savedTo : skip.front();
}
} // namespace Ui

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/object_ptr.h"
class History;
class PeerData;
struct LanguageId;
@ -27,6 +28,19 @@ void TranslateBox(
[[nodiscard]] bool SkipTranslate(TextWithEntities textWithEntities);
[[nodiscard]] object_ptr<BoxContent> EditSkipTranslationLanguages();
[[nodiscard]] object_ptr<BoxContent> ChooseTranslateToBox();
[[nodiscard]] object_ptr<BoxContent> ChooseTranslateToBox(
LanguageId bringUp,
Fn<void(LanguageId)> callback);
[[nodiscard]] LanguageId ChooseTranslateTo(not_null<History*> history);
[[nodiscard]] LanguageId ChooseTranslateTo(LanguageId offeredFrom);
[[nodiscard]] LanguageId ChooseTranslateTo(
not_null<History*> history,
LanguageId savedTo,
const std::vector<LanguageId> &skip);
[[nodiscard]] LanguageId ChooseTranslateTo(
LanguageId offeredFrom,
LanguageId savedTo,
const std::vector<LanguageId> &skip);
} // namespace Ui

View file

@ -14,7 +14,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "spellcheck/spellcheck_types.h"
#include "ui/effects/ripple_animation.h"
#include "ui/boxes/choose_language_box.h" // EditSkipTranslationLanguages.
#include "ui/layers/box_content.h"
@ -294,14 +293,6 @@ void TranslateBar::setup(not_null<History*> history) {
: Core::App().settings().translateTo());
});
Core::App().settings().translateToValue(
) | rpl::filter([=](LanguageId should) {
const auto now = history->translatedTo();
return now && (now != should);
}) | rpl::start_with_next([=](LanguageId should) {
translateTo(should);
}, _wrap.lifetime());
const auto label = Ui::CreateChild<Ui::FlatLabel>(
button,
st::historyTranslateLabel);
@ -343,8 +334,34 @@ void TranslateBar::setup(not_null<History*> history) {
updateLabelGeometry();
}, lifetime());
rpl::combine(
_overridenTo = history->translatedTo();
_to = rpl::combine(
Core::App().settings().translateToValue(),
Core::App().settings().skipTranslationLanguagesValue(),
history->session().changes().historyFlagsValue(
history,
Data::HistoryUpdate::Flag::TranslateFrom),
_overridenTo.value()
) | rpl::map([=](
LanguageId to,
const std::vector<LanguageId> &skip,
const auto &,
LanguageId overridenTo) {
return overridenTo
? overridenTo
: Ui::ChooseTranslateTo(history, to, skip);
}) | rpl::distinct_until_changed();
_to.value(
) | rpl::filter([=](LanguageId should) {
const auto now = history->translatedTo();
return now && (now != should);
}) | rpl::start_with_next([=](LanguageId should) {
translateTo(should);
}, _wrap.lifetime());
rpl::combine(
_to.value(),
history->session().changes().historyFlagsValue(
history,
(Data::HistoryUpdate::Flag::TranslatedTo
@ -352,16 +369,17 @@ void TranslateBar::setup(not_null<History*> history) {
history->session().changes().peerFlagsValue(
history->peer,
Data::PeerUpdate::Flag::TranslationDisabled)
) | rpl::map([=](LanguageId to, const auto&, const auto&) {
) | rpl::map([=](
LanguageId to,
const auto&,
const auto&) {
using Flag = PeerData::TranslationFlag;
return (history->peer->translationFlag() != Flag::Enabled)
? rpl::single(QString())
: history->translatedTo()
? tr::lng_translate_show_original()
: history->translateOfferedFrom()
? tr::lng_translate_bar_to(
lt_name,
rpl::single(Ui::LanguageName(to)))
? Ui::TranslateBarTo(to)
: rpl::single(QString());
}) | rpl::flatten_latest(
) | rpl::distinct_until_changed(
@ -408,20 +426,25 @@ void TranslateBar::showMenu(base::unique_qptr<Ui::PopupMenu> menu) {
_menu = std::move(menu);
_menu->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
const auto guard = Ui::MakeWeak(&_wrap);
const auto now = _history->translatedTo();
const auto to = now ? now : Ui::ChooseTranslateTo(_history);
const auto weak = base::make_weak(_controller);
const auto chooseCallback = [=] {
if (const auto strong = weak.get()) {
strong->show(Ui::ChooseTranslateToBox());
strong->show(Ui::ChooseTranslateToBox(
to,
crl::guard(guard, [=](LanguageId id) { _overridenTo = id; })
));
}
};
_menu->addAction(MakeTranslateToItem(
_menu->menu(),
Ui::LanguageName(Core::App().settings().translateTo()),
Ui::LanguageName(to ? to : Ui::ChooseTranslateTo(_history)),
chooseCallback));
_menu->addSeparator();
const auto history = _history;
if (const auto translateOfferedFrom = _history->translateOfferedFrom()) {
const auto name = Ui::LanguageName(translateOfferedFrom);
const auto addToIgnoreList = [=] {
showSettingsToast(history->peer, translateOfferedFrom);
@ -436,7 +459,7 @@ void TranslateBar::showMenu(base::unique_qptr<Ui::PopupMenu> menu) {
Core::App().saveSettingsDelayed();
};
_menu->addAction(
tr::lng_translate_menu_dont(tr::now, lt_name, name),
Ui::TranslateMenuDont(tr::now, translateOfferedFrom),
addToIgnoreList,
&st::menuIconBlock);
}

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "ui/wrap/slide_wrap.h"
#include "spellcheck/spellcheck_types.h"
class History;
struct LanguageId;
@ -68,6 +69,8 @@ private:
std::unique_ptr<Ui::PlainShadow> _shadow;
Fn<QRect(QRect)> _shadowGeometryPostprocess;
base::unique_qptr<Ui::PopupMenu> _menu;
rpl::variable<LanguageId> _overridenTo;
rpl::variable<LanguageId> _to;
bool _shouldBeShown = false;
bool _forceHidden = false;

View file

@ -234,7 +234,7 @@ void TranslateTracker::requestSome() {
peer->input,
MTP_vector<MTPint>(list),
MTPVector<MTPTextWithEntities>(),
MTP_string(to.locale().name().mid(0, 2))
MTP_string(to.twoLetterCode())
)).done([=](const MTPmessages_TranslatedText &result) {
requestDone(to, result.data().vresult().v);
}).fail([=] {

View file

@ -22,7 +22,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
namespace {
const auto kLanguageNamePrefix = "cloud_lng_passport_in_";
const auto kLanguageNamePrefix = "cloud_lng_language_";
const auto kTranslateToPrefix = "cloud_lng_translate_to_";
[[nodiscard]] std::vector<LanguageId> TranslationLanguagesList() {
// If adding some languages here you need to check that it is
@ -214,12 +215,13 @@ QString LanguageNameTranslated(const QString &twoLetterCode) {
kLanguageNamePrefix + twoLetterCode.toUtf8());
}
QString LanguageNameLocal(LanguageId id) {
return QLocale::languageToString(id.language());
}
QString LanguageName(LanguageId id) {
const auto code = id.locale().name().toLower().mid(0, 2);
const auto translated = LanguageNameTranslated(code);
return translated.isEmpty()
? QLocale::languageToString(id.locale().language())
: translated;
const auto translated = LanguageNameTranslated(id.twoLetterCode());
return translated.isEmpty() ? LanguageNameLocal(id) : translated;
}
QString LanguageNameNative(LanguageId id) {
@ -236,6 +238,29 @@ QString LanguageNameNative(LanguageId id) {
}
}
rpl::producer<QString> TranslateBarTo(LanguageId id) {
const auto translated = Lang::GetNonDefaultValue(
kTranslateToPrefix + id.twoLetterCode().toUtf8());
return (translated.isEmpty()
? tr::lng_translate_bar_to_other
: tr::lng_translate_bar_to)(
lt_name,
rpl::single(translated.isEmpty()
? LanguageNameLocal(id)
: translated));
}
QString TranslateMenuDont(tr::now_t, LanguageId id) {
const auto translated = Lang::GetNonDefaultValue(
kTranslateToPrefix + id.twoLetterCode().toUtf8());
return (translated.isEmpty()
? tr::lng_translate_menu_dont_other
: tr::lng_translate_menu_dont)(
tr::now,
lt_name,
translated.isEmpty() ? LanguageNameLocal(id) : translated);
}
void ChooseLanguageBox(
not_null<GenericBox*> box,
rpl::producer<QString> title,
@ -256,6 +281,9 @@ void ChooseLanguageBox(
const auto container = box->verticalLayout();
const auto langs = [&] {
auto list = TranslationLanguagesList();
for (const auto id : list) {
LOG(("cloud_lng_language_%1").arg(id.twoLetterCode()));
}
const auto current = LanguageId{ QLocale(
Lang::LanguageIdOrDefault(Lang::Id())).language() };
if (const auto i = ranges::find(list, current); i != end(list)) {

View file

@ -9,14 +9,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
struct LanguageId;
namespace tr {
struct now_t;
} // namespace tr
namespace Ui {
class GenericBox;
[[nodiscard]] QString LanguageNameTranslated(const QString &twoLetterCode);
[[nodiscard]] QString LanguageNameLocal(LanguageId id);
[[nodiscard]] QString LanguageName(LanguageId id);
[[nodiscard]] QString LanguageNameNative(LanguageId id);
[[nodiscard]] rpl::producer<QString> TranslateBarTo(LanguageId id);
[[nodiscard]] QString TranslateMenuDont(tr::now_t, LanguageId id);
void ChooseLanguageBox(
not_null<GenericBox*> box,
rpl::producer<QString> title,

@ -1 +1 @@
Subproject commit 55ed1489ffac0b60adbd427c2b76be1ce55194e7
Subproject commit ae89fefd239ecc47d4dab7ba29f9e230376a57d3