diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index d105df8a..0edabc00 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3131,8 +3131,8 @@ getSupportUser = User; getWallpapers = Wallpapers; -//@description Returns information about the current localization target -getLocalizationTargetInfo = LocalizationTargetInfo; +//@description Returns information about the current localization target. This is an offline request if only_local is true @only_local If true, returns only locally available information without sending network requests +getLocalizationTargetInfo only_local:Bool = LocalizationTargetInfo; //@description Returns strings from a language pack in the current localization target by their keys @language_pack_id Language pack identifier of the strings to be returned @keys Language pack keys of the strings to be returned; leave empty to request all available strings getLanguagePackStrings language_pack_id:string keys:vector = LanguagePackStrings; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 1945a205..4b2e788c 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index 15e97d8e..913d6062 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -56,12 +57,17 @@ struct LanguagePackManager::Language { struct LanguagePackManager::LanguageInfo { string name; string native_name; + + friend bool operator==(const LanguageInfo &lhs, const LanguageInfo &rhs) { + return lhs.name == rhs.name && lhs.native_name == rhs.native_name; + } }; struct LanguagePackManager::LanguagePack { std::mutex mutex_; - SqliteKeyValue pack_kv_; // usages should be guarded by database_->mutex_ - std::unordered_map language_infos_; + SqliteKeyValue pack_kv_; // usages should be guarded by database_->mutex_ + std::map custom_language_pack_infos_; // sorted by language_code + vector> server_language_pack_infos_; // sorted by server std::unordered_map> languages_; }; @@ -341,8 +347,24 @@ LanguagePackManager::Language *LanguagePackManager::add_language(LanguageDatabas pack->pack_kv_.init_with_connection(database->database_.clone(), get_database_table_name(language_pack, "0")) .ensure(); for (auto &lang : pack->pack_kv_.get_all()) { + if (lang.first == "!server") { + auto all_infos = full_split(lang.second, '\x00'); + if (all_infos.size() % 3 == 0) { + for (size_t i = 0; i < all_infos.size(); i += 3) { + LanguageInfo info; + info.name = std::move(all_infos[i + 1]); + info.native_name = std::move(all_infos[i + 2]); + pack->server_language_pack_infos_.emplace_back(std::move(all_infos[i]), std::move(info)); + } + } else { + LOG(ERROR) << "Have wrong language pack info \"" << lang.second << "\" in the database"; + } + + continue; + } + auto names = split(lang.second, '\x00'); - auto &info = pack->language_infos_[lang.first]; + auto &info = pack->custom_language_pack_infos_[lang.first]; info.name = std::move(names.first); info.native_name = std::move(names.second); } @@ -549,11 +571,17 @@ td_api::object_ptr LanguagePackManager::get_languag return td_api::make_object(std::move(strings)); } -void LanguagePackManager::get_languages(Promise> promise) { +void LanguagePackManager::get_languages(bool only_local, + Promise> promise) { if (language_pack_.empty()) { return promise.set_error(Status::Error(400, "Option \"localization_target\" needs to be set first")); } + if (only_local) { + return on_get_languages(vector>(), language_pack_, true, + std::move(promise)); + } + auto request_promise = PromiseCreator::lambda([actor_id = actor_id(this), language_pack = language_pack_, promise = std::move(promise)](Result r_query) mutable { auto r_result = fetch_result(std::move(r_query)); @@ -562,14 +590,14 @@ void LanguagePackManager::get_languages(Promisenet_query_creator().create(create_storer(telegram_api::langpack_getLanguages(language_pack_))), std::move(request_promise)); } void LanguagePackManager::on_get_languages(vector> languages, - string language_pack, + string language_pack, bool only_local, Promise> promise) { auto results = td_api::make_object(); @@ -578,28 +606,62 @@ void LanguagePackManager::on_get_languages(vectorlanguage_packs_.find(language_pack); if (pack_it != database_->language_packs_.end()) { LanguagePack *pack = pack_it->second.get(); - for (auto &info : pack->language_infos_) { + for (auto &info : pack->custom_language_pack_infos_) { results->language_packs_.push_back( make_tl_object(info.first, info.second.name, info.second.native_name, 0)); } + if (only_local) { + for (auto &info : pack->server_language_pack_infos_) { + results->language_packs_.push_back( + make_tl_object(info.first, info.second.name, info.second.native_name, 0)); + } + } } } + vector> all_server_infos; for (auto &language : languages) { - results->language_packs_.push_back( - make_tl_object(language->lang_code_, language->name_, language->native_name_, 0)); - } - - for (auto &language_info : results->language_packs_) { - if (!check_language_code_name(language_info->id_)) { - LOG(ERROR) << "Receive unsupported language pack ID " << language_info->id_ << " from server"; + if (!check_language_code_name(language->lang_code_)) { + LOG(ERROR) << "Receive unsupported language pack ID " << language->lang_code_ << " from server"; continue; } + results->language_packs_.push_back( + make_tl_object(language->lang_code_, language->name_, language->native_name_, 0)); + + LanguageInfo info; + info.name = std::move(language->name_); + info.native_name = std::move(language->native_name_); + all_server_infos.emplace_back(std::move(language->lang_code_), std::move(info)); + } + + for (auto &language_info : results->language_packs_) { auto language = add_language(database_, language_pack, language_info->id_); language_info->local_string_count_ = language->key_count_; } + if (!only_local) { + std::lock_guard packs_lock(database_->mutex_); + auto pack_it = database_->language_packs_.find(language_pack); + if (pack_it != database_->language_packs_.end()) { + LanguagePack *pack = pack_it->second.get(); + if (pack->server_language_pack_infos_ != all_server_infos) { + pack->server_language_pack_infos_ = std::move(all_server_infos); + + if (!pack->pack_kv_.empty()) { + vector all_strings; + all_strings.reserve(3 * pack->server_language_pack_infos_.size()); + for (auto &info : pack->server_language_pack_infos_) { + all_strings.push_back(info.first); + all_strings.push_back(info.second.name); + all_strings.push_back(info.second.native_name); + } + + pack->pack_kv_.set("!server", implode(all_strings, '\x00')); + } + } + } + } promise.set_value(std::move(results)); } @@ -1065,7 +1127,7 @@ void LanguagePackManager::set_custom_language(string language_code, string langu auto pack_it = database_->language_packs_.find(language_pack_); CHECK(pack_it != database_->language_packs_.end()); LanguagePack *pack = pack_it->second.get(); - auto &info = pack->language_infos_[language_code]; + auto &info = pack->custom_language_pack_infos_[language_code]; info.name = std::move(language_name); info.native_name = std::move(language_native_name); if (!pack->pack_kv_.empty()) { @@ -1091,8 +1153,8 @@ void LanguagePackManager::edit_custom_language_info(string language_code, string auto pack_it = database_->language_packs_.find(language_pack_); CHECK(pack_it != database_->language_packs_.end()); LanguagePack *pack = pack_it->second.get(); - auto language_info_it = pack->language_infos_.find(language_code); - if (language_info_it == pack->language_infos_.end()) { + auto language_info_it = pack->custom_language_pack_infos_.find(language_code); + if (language_info_it == pack->custom_language_pack_infos_.end()) { return promise.set_error(Status::Error(400, "Custom language pack is not found")); } auto &info = language_info_it->second; @@ -1197,7 +1259,7 @@ Status LanguagePackManager::do_delete_language(string language_code) { if (!pack->pack_kv_.empty()) { pack->pack_kv_.erase(language_code); } - pack->language_infos_.erase(language_code); + pack->custom_language_pack_infos_.erase(language_code); } return Status::OK(); diff --git a/td/telegram/LanguagePackManager.h b/td/telegram/LanguagePackManager.h index bf470890..5992226c 100644 --- a/td/telegram/LanguagePackManager.h +++ b/td/telegram/LanguagePackManager.h @@ -48,7 +48,7 @@ class LanguagePackManager : public NetQueryCallback { void on_language_pack_version_changed(int32 new_version); - void get_languages(Promise> promise); + void get_languages(bool only_local, Promise> promise); void get_language_pack_strings(string language_code, vector keys, Promise> promise); @@ -147,7 +147,7 @@ class LanguagePackManager : public NetQueryCallback { void on_failed_get_difference(string language_pack, string language_code); void on_get_languages(vector> languages, string language_pack, - Promise> promise); + bool only_local, Promise> promise); Status do_delete_language(string language_code); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index d2d3b6e1..1e771a13 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6042,7 +6042,7 @@ void Td::on_request(uint64 id, const td_api::getMapThumbnailFile &request) { void Td::on_request(uint64 id, const td_api::getLocalizationTargetInfo &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::get_languages, std::move(promise)); + send_closure(language_pack_manager_, &LanguagePackManager::get_languages, request.only_local_, std::move(promise)); } void Td::on_request(uint64 id, td_api::getLanguagePackStrings &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index fe5d9ed1..72ac225c 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1751,7 +1751,7 @@ class CliClient final : public Actor { std::tie(chat_id, message_id) = split(args); send_request(make_tl_object(as_chat_id(chat_id), as_message_id(message_id))); } else if (op == "glti") { - send_request(make_tl_object()); + send_request(make_tl_object(as_bool(args))); } else if (op == "glps") { string language_code; string keys;