From 350e7fd6fcecfc2c7da9f436c8dd2be670de67cc Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 11 Feb 2019 20:57:35 +0300 Subject: [PATCH] Support new languagePackInfo fields. GitOrigin-RevId: ad99afe9694458448fddc84803a8beeb33a64a70 --- td/generate/scheme/td_api.tl | 27 +-- td/generate/scheme/td_api.tlo | Bin 144140 -> 144456 bytes td/telegram/LanguagePackManager.cpp | 268 +++++++++++++++++++++++----- td/telegram/LanguagePackManager.h | 11 +- td/telegram/Td.cpp | 21 +-- td/telegram/cli.cpp | 23 ++- 6 files changed, 267 insertions(+), 83 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 5fadf7a72..c43fde9b3 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -91,7 +91,7 @@ authorizationStateWaitPhoneNumber = AuthorizationState; //@description TDLib needs the user's authentication code to finalize authorization @is_registered True, if the user is already registered @terms_of_service Telegram terms of service, which should be accepted before user can continue registration; may be null @code_info Information about the authorization code that was sent authorizationStateWaitCode is_registered:Bool terms_of_service:termsOfService code_info:authenticationCodeInfo = AuthorizationState; -//@description The user has been authorized, but needs to enter a password to start using the application @password_hint Hint for the password; can be empty @has_recovery_email_address True if a recovery email address has been set up +//@description The user has been authorized, but needs to enter a password to start using the application @password_hint Hint for the password; may be empty @has_recovery_email_address True if a recovery email address has been set up //@recovery_email_address_pattern Pattern of the email address to which the recovery email was sent; empty until a recovery email has been sent authorizationStateWaitPassword password_hint:string has_recovery_email_address:Bool recovery_email_address_pattern:string = AuthorizationState; @@ -109,7 +109,7 @@ authorizationStateClosing = AuthorizationState; authorizationStateClosed = AuthorizationState; -//@description Represents the current state of 2-step verification @has_password True, if a 2-step verification password is set @password_hint Hint for the password; can be empty +//@description Represents the current state of 2-step verification @has_password True, if a 2-step verification password is set @password_hint Hint for the password; may be empty //@has_recovery_email_address True, if a recovery email is set @has_passport_data True, if some Telegram Passport elements were saved //@recovery_email_address_code_info Information about the recovery email address to which the confirmation email was sent; may be null passwordState has_password:Bool password_hint:string has_recovery_email_address:Bool has_passport_data:Bool recovery_email_address_code_info:emailAddressAuthenticationCodeInfo = PasswordState; @@ -743,8 +743,8 @@ pageBlockVerticalAlignmentBottom = PageBlockVerticalAlignment; //@align Horizontal cell content alignment @valign Vertical cell content alignment pageBlockTableCell text:RichText is_header:Bool colspan:int32 rowspan:int32 align:PageBlockHorizontalAlignment valign:PageBlockVerticalAlignment = PageBlockTableCell; -//@description Contains information about a related article @url Related article URL @title Article title; can be empty @param_description Article description, can be empty -//@photo Article photo; may be null @author Article author, can be empty @published_date Article publish date; 0 if unknown +//@description Contains information about a related article @url Related article URL @title Article title; may be empty @param_description Article description; may be empty +//@photo Article photo; may be null @author Article author; may be empty @published_date Article publish date; 0 if unknown pageBlockRelatedArticle url:string title:string description:string photo:photo author:string published_date:int32 = PageBlockRelatedArticle; @@ -1118,7 +1118,7 @@ passportRequiredElement suitable_elements:vector = Pass //@description Contains information about a Telegram Passport authorization form that was requested @id Unique identifier of the authorization form //@required_elements Information about the Telegram Passport elements that need to be provided to complete the form -//@privacy_policy_url URL for the privacy policy of the service; can be empty +//@privacy_policy_url URL for the privacy policy of the service; may be empty passportAuthorizationForm id:int32 required_elements:vector privacy_policy_url:string = PassportAuthorizationForm; //@description Contains information about a Telegram Passport elements and corresponding errors @elements Telegram Passport elements @errors Errors in the elements that are already available @@ -1265,7 +1265,7 @@ messageChatSetTtl ttl:int32 = MessageContent; //@description A non-standard action has happened in the chat @text Message text to be shown in the chat messageCustomServiceAction text:string = MessageContent; -//@description A new high score was achieved in a game @game_message_id Identifier of the message with the game, can be an identifier of a deleted message @game_id Identifier of the game, may be different from the games presented in the message with the game @score New score +//@description A new high score was achieved in a game @game_message_id Identifier of the message with the game, can be an identifier of a deleted message @game_id Identifier of the game; may be different from the games presented in the message with the game @score New score messageGameScore game_message_id:int53 game_id:int64 score:int32 = MessageContent; //@description A payment has been completed @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the minimal quantity of the currency @@ -1804,7 +1804,8 @@ chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool //@description An ordinary language pack string @value String value languagePackStringValueOrdinary value:string = LanguagePackStringValue; -//@description A language pack string which has different forms based on the number of some object it mentions @zero_value Value for zero objects @one_value Value for one object @two_value Value for two objects +//@description A language pack string which has different forms based on the number of some object it mentions. See https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html for more info +//@zero_value Value for zero objects @one_value Value for one object @two_value Value for two objects //@few_value Value for few objects @many_value Value for many objects @other_value Default value languagePackStringValuePluralized zero_value:string one_value:string two_value:string few_value:string many_value:string other_value:string = LanguagePackStringValue; @@ -1818,8 +1819,14 @@ languagePackString key:string value:LanguagePackStringValue = LanguagePackString //@description Contains a list of language pack strings @strings A list of language pack strings languagePackStrings strings:vector = LanguagePackStrings; -//@description Contains information about a language pack @id Unique language pack identifier @name Language name @native_name Name of the language in that language @local_string_count Total number of non-deleted strings from the language pack available locally -languagePackInfo id:string name:string native_name:string local_string_count:int32 = LanguagePackInfo; +//@description Contains information about a language pack @id Unique language pack identifier +//@base_language_pack_id Identifier of a base language pack; may be empty. If a string is missed in the language pack, then it should be fetched from base language pack. Unsupported in custom language packs +//@name Language name @native_name Name of the language in that language +//@plural_code A language code to be used to apply plural forms. See https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html for more info +//@is_official True, if the language pack is official @is_rtl True, if the language pack strings are RTL @is_beta True, if the language pack is a beta language pack +//@total_string_count Total number of non-deleted strings from the language pack @translated_string_count Total number of translated strings from the language pack +//@local_string_count Total number of non-deleted strings from the language pack available locally @translation_url Link to language translation interface; empty for custom local language packs +languagePackInfo id:string base_language_pack_id:string name:string native_name:string plural_code:string is_official:Bool is_rtl:Bool is_beta:Bool total_string_count:int32 translated_string_count:int32 local_string_count:int32 translation_url:string = LanguagePackInfo; //@description Contains information about the current localization target @language_packs List of available language packs for this application localizationTargetInfo language_packs:vector = LocalizationTargetInfo; @@ -3132,7 +3139,7 @@ importContacts contacts:vector = ImportedContacts; //@description Returns all user contacts getContacts = Users; -//@description Searches for the specified query in the first names, last names and usernames of the known user contacts @query Query to search for; can be empty to return all contacts @limit Maximum number of users to be returned +//@description Searches for the specified query in the first names, last names and usernames of the known user contacts @query Query to search for; may be empty to return all contacts @limit Maximum number of users to be returned searchContacts query:string limit:int32 = Users; //@description Removes users from the contact list @user_ids Identifiers of users to be deleted diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 64b38341895aba83e319fba072c12d372c509155..4a3fbf8c540fd51639745fa9a3a0ee4c5c3db479 100644 GIT binary patch delta 233 zcmeBq#&O~W#|8lbmPJW>*)iIWws zO7fKCmn7!I7nc-e=A}=+Xv-)sBwkXKm{**WSdy9o6R&e%l$$(dzsB?lUl>_=VDg#y zdGV7sTFXP+cw&DFD}-fm)a4VHHEk-R!uA>488Z^VZf0Zvg2|4D?57J%Wfa&RA;Gjo F3ILinSuOwo delta 96 zcmX@{f}`gd#|8lbmPr-(mV+s* g5LV7Hmrr2U^aEl{ircU5U`$T{^S3)lGI2-)0CD{#<^TWy diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index f739e9448..306aaad1a 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -14,6 +14,7 @@ #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/Td.h" +#include "td/telegram/misc.h" #include "td/telegram/td_api.h" #include "td/telegram/td_api.hpp" #include "td/telegram/telegram_api.h" @@ -57,11 +58,23 @@ struct LanguagePackManager::Language { }; struct LanguagePackManager::LanguageInfo { - string name; - string native_name; + string name_; + string native_name_; + string base_language_code_; + string plural_code_; + bool is_official_ = false; + bool is_rtl_ = false; + bool is_beta_ = false; + int32 total_string_count_ = 0; // TODO move to LanguagePack and calculate as max(total_string_count) + int32 translated_string_count_ = 0; + string translation_url_; friend bool operator==(const LanguageInfo &lhs, const LanguageInfo &rhs) { - return lhs.name == rhs.name && lhs.native_name == rhs.native_name; + return lhs.name_ == rhs.name_ && lhs.native_name_ == rhs.native_name_ && + lhs.base_language_code_ == rhs.base_language_code_ && lhs.plural_code_ == rhs.plural_code_ && + lhs.is_official_ == rhs.is_official_ && lhs.is_rtl_ == rhs.is_rtl_ && lhs.is_beta_ == rhs.is_beta_ && + lhs.total_string_count_ == rhs.total_string_count_ && + lhs.translated_string_count_ == rhs.translated_string_count_ && lhs.translation_url_ == rhs.translation_url_; } }; @@ -195,7 +208,7 @@ void LanguagePackManager::start_up() { std::lock_guard language_lock(language->mutex_); base_language_code_ = language->base_language_code_; if (!check_language_code_name(base_language_code_)) { - LOG(ERROR) << "Have invalid base language code name \"" << base_language_code_ << '"'; + LOG(ERROR) << "Have invalid base language pack ID \"" << base_language_code_ << '"'; base_language_code_.clear(); } if (!base_language_code_.empty()) { @@ -372,7 +385,7 @@ void LanguagePackManager::inc_generation() { std::lock_guard lock(language->mutex_); base_language_code_ = language->base_language_code_; if (!check_language_code_name(base_language_code_)) { - LOG(ERROR) << "Have invalid base language code name \"" << base_language_code_ << '"'; + LOG(ERROR) << "Have invalid base language pack ID \"" << base_language_code_ << '"'; base_language_code_.clear(); } if (!base_language_code_.empty()) { @@ -420,27 +433,68 @@ LanguagePackManager::Language *LanguagePackManager::add_language(LanguageDatabas if (!database->database_.empty()) { pack->pack_kv_.init_with_connection(database->database_.clone(), get_database_table_name(language_pack, "0")) .ensure(); + bool need_drop_server = false; for (auto &lang : pack->pack_kv_.get_all()) { + auto as_bool = [](Slice data) { + if (data == "true") { + return true; + } + if (data != "false") { + LOG(ERROR) << "Have invalid boolean value \"" << data << "\" in the database"; + } + return false; + }; + if (lang.first == "!server") { + // legacy info format, drop cache + need_drop_server = true; + continue; + } + if (lang.first == "!server2") { 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) { + if (all_infos.size() % 11 == 0) { + for (size_t i = 0; i < all_infos.size(); i += 11) { LanguageInfo info; - info.name = std::move(all_infos[i + 1]); - info.native_name = std::move(all_infos[i + 2]); + info.name_ = std::move(all_infos[i + 1]); + info.native_name_ = std::move(all_infos[i + 2]); + info.base_language_code_ = std::move(all_infos[i + 3]); + info.plural_code_ = std::move(all_infos[i + 4]); + info.is_official_ = as_bool(all_infos[i + 5]); + info.is_rtl_ = as_bool(all_infos[i + 6]); + info.is_beta_ = as_bool(all_infos[i + 7]); + info.total_string_count_ = to_integer(all_infos[i + 8]); + info.translated_string_count_ = to_integer(all_infos[i + 9]); + info.translation_url_ = std::move(all_infos[i + 10]); 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 all_infos = full_split(lang.second, '\x00'); + if (all_infos.size() < 2) { + LOG(ERROR) << "Have wrong custom language pack info \"" << lang.second << '"'; + continue; + } auto &info = pack->custom_language_pack_infos_[lang.first]; - info.name = std::move(names.first); - info.native_name = std::move(names.second); + info.name_ = std::move(all_infos[0]); + info.native_name_ = std::move(all_infos[1]); + if (all_infos.size() >= 2) { + CHECK(all_infos.size() == 10); + info.base_language_code_ = std::move(all_infos[2]); + info.plural_code_ = std::move(all_infos[3]); + info.is_official_ = as_bool(all_infos[4]); + info.is_rtl_ = as_bool(all_infos[5]); + info.is_beta_ = as_bool(all_infos[6]); + info.total_string_count_ = to_integer(all_infos[7]); + info.translated_string_count_ = to_integer(all_infos[8]); + info.translation_url_ = std::move(all_infos[9]); + } + } + if (need_drop_server) { + pack->pack_kv_.erase("!server"); } } pack_it = database->language_packs_.emplace(language_pack, std::move(pack)).first; @@ -673,10 +727,31 @@ void LanguagePackManager::get_languages(bool only_local, std::move(request_promise)); } +td_api::object_ptr LanguagePackManager::get_language_pack_info_object( + const string &language_code, const LanguageInfo &info) { + return td_api::make_object( + language_code, info.base_language_code_, info.name_, info.native_name_, info.plural_code_, info.is_official_, + info.is_rtl_, info.is_beta_, info.total_string_count_, info.translated_string_count_, 0, info.translation_url_); +} + +string LanguagePackManager::get_language_info_string(const LanguageInfo &info) { + return PSTRING() << info.name_ << '\x00' << info.native_name_ << '\x00' << info.base_language_code_ << '\x00' + << info.plural_code_ << '\x00' << info.is_official_ << '\x00' << info.is_rtl_ << '\x00' + << info.is_beta_ << '\x00' << info.total_string_count_ << '\x00' << info.translated_string_count_ + << '\x00' << info.translation_url_; +} + void LanguagePackManager::on_get_languages(vector> languages, string language_pack, bool only_local, Promise> promise) { auto results = td_api::make_object(); + std::unordered_set added_languages; + + auto add_language_info = [&results, &added_languages](const string &language_code, const LanguageInfo &info) { + if (added_languages.insert(language_code).second) { + results->language_packs_.push_back(get_language_pack_info_object(language_code, info)); + } + }; { std::lock_guard packs_lock(database_->mutex_); @@ -684,13 +759,11 @@ void LanguagePackManager::on_get_languages(vectorlanguage_packs_.end()) { LanguagePack *pack = pack_it->second.get(); 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)); + add_language_info(info.first, info.second); } 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)); + add_language_info(info.first, info.second); } } } @@ -703,23 +776,68 @@ void LanguagePackManager::on_get_languages(vectorlang_code_)) { - LOG(ERROR) << "Receive custom language pack ID " << language->lang_code_ << " from server"; + LOG(ERROR) << "Receive custom 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_); + info.name_ = std::move(language->name_); + info.native_name_ = std::move(language->native_name_); + info.base_language_code_ = std::move(language->base_lang_code_); + info.plural_code_ = std::move(language->plural_code_); + info.is_official_ = (language->flags_ & telegram_api::langPackLanguage::OFFICIAL_MASK) != 0; + info.is_rtl_ = (language->flags_ & telegram_api::langPackLanguage::RTL_MASK) != 0; + info.is_beta_ = (language->flags_ & telegram_api::langPackLanguage::BETA_MASK) != 0; + info.total_string_count_ = language->strings_count_; + info.translated_string_count_ = language->translated_count_; + info.translation_url_ = language->translations_url_; + + if (!check_language_code_name(info.base_language_code_)) { + LOG(ERROR) << "Have invalid base language pack ID \"" << info.base_language_code_ << '"'; + info.base_language_code_.clear(); + } + if (is_custom_language_code(info.base_language_code_)) { + LOG(ERROR) << "Receive custom base language pack ID \"" << info.base_language_code_ << "\" from server"; + info.base_language_code_.clear(); + } + if (info.base_language_code_ == language->lang_code_) { + LOG(ERROR) << "Receive language pack \"" << info.base_language_code_ << "\"based on self"; + info.base_language_code_.clear(); + } + + add_language_info(language->lang_code_, info); 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_; - // TODO if (language_info->base_language_pack_name != language->base_language_pack_name) update it + SqliteKeyValue *kv = nullptr; + bool was_updated_base_language_code = false; + { + std::lock_guard lock(language->mutex_); + if (language_info->base_language_pack_id_ != language->base_language_code_) { + language->base_language_code_ = language_info->base_language_pack_id_; + if (language_info->id_ == language_code_) { + base_language_code_ = language->base_language_code_; + was_updated_base_language_code = true; + } + if (!language->kv_.empty()) { + kv = &language->kv_; + } + } + } + if (was_updated_base_language_code) { + G()->shared_config().set_option_empty("base_language_pack_version"); + if (!base_language_code_.empty()) { + add_language(database_, language_pack_, base_language_code_); + on_language_pack_version_changed(true, std::numeric_limits::max()); + } + } + if (kv != nullptr) { + std::lock_guard lock(database_->mutex_); + kv->set("!base_language_code", language_info->base_language_pack_id_); + } } if (!only_local) { @@ -732,14 +850,13 @@ void LanguagePackManager::on_get_languages(vectorpack_kv_.empty()) { vector all_strings; - all_strings.reserve(3 * pack->server_language_pack_infos_.size()); + all_strings.reserve(2 * 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); + all_strings.push_back(get_language_info_string(info.second)); } - pack->pack_kv_.set("!server", implode(all_strings, '\x00')); + pack->pack_kv_.set("!server2", implode(all_strings, '\x00')); } } } @@ -1191,15 +1308,75 @@ Result> LanguagePackManager::convert } } -void LanguagePackManager::set_custom_language(string language_code, string language_name, string language_native_name, +Result LanguagePackManager::get_language_info( + td_api::languagePackInfo *language_pack_info) { + if (language_pack_info == nullptr) { + return Status::Error(400, "Language pack info must not be empty"); + } + + if (!clean_input_string(language_pack_info->id_)) { + return Status::Error(400, "Language pack ID must be encoded in UTF-8"); + } + if (!clean_input_string(language_pack_info->base_language_pack_id_)) { + return Status::Error(400, "Base language pack ID must be encoded in UTF-8"); + } + if (!clean_input_string(language_pack_info->name_)) { + return Status::Error(400, "Language pack name must be encoded in UTF-8"); + } + if (!clean_input_string(language_pack_info->native_name_)) { + return Status::Error(400, "Language pack native name must be encoded in UTF-8"); + } + if (!clean_input_string(language_pack_info->plural_code_)) { + return Status::Error(400, "Language pack plural code must be encoded in UTF-8"); + } + if (!clean_input_string(language_pack_info->translation_url_)) { + return Status::Error(400, "Language pack translation url must be encoded in UTF-8"); + } + if (language_pack_info->total_string_count_ < 0) { + language_pack_info->total_string_count_ = 0; + } + if (language_pack_info->translated_string_count_ < 0) { + language_pack_info->translated_string_count_ = 0; + } + if (!check_language_code_name(language_pack_info->id_)) { + return Status::Error(400, "Language pack ID must contain only letters, digits and hyphen"); + } + + if (is_custom_language_code(language_pack_info->id_)) { + language_pack_info->base_language_pack_id_.clear(); + language_pack_info->is_official_ = false; + language_pack_info->is_rtl_ = false; + language_pack_info->is_beta_ = false; + language_pack_info->translation_url_.clear(); + } + + LanguageInfo info; + info.name_ = std::move(language_pack_info->name_); + info.native_name_ = std::move(language_pack_info->native_name_); + info.base_language_code_ = std::move(language_pack_info->base_language_pack_id_); + info.plural_code_ = std::move(language_pack_info->plural_code_); + info.is_official_ = language_pack_info->is_official_; + info.is_rtl_ = language_pack_info->is_rtl_; + info.is_beta_ = language_pack_info->is_beta_; + info.total_string_count_ = language_pack_info->total_string_count_; + info.translated_string_count_ = language_pack_info->translated_string_count_; + info.translation_url_ = std::move(language_pack_info->translation_url_); + + return std::move(info); +} + +void LanguagePackManager::set_custom_language(td_api::object_ptr &&language_pack_info, vector> strings, Promise &&promise) { if (language_pack_.empty()) { return promise.set_error(Status::Error(400, "Option \"localization_target\" needs to be set first")); } - if (!check_language_code_name(language_code)) { - return promise.set_error(Status::Error(400, "Language pack ID must contain only letters, digits and hyphen")); + + auto r_info = get_language_info(language_pack_info.get()); + if (r_info.is_error()) { + return promise.set_error(r_info.move_as_error()); } + auto language_code = std::move(language_pack_info->id_); if (!is_custom_language_code(language_code)) { return promise.set_error(Status::Error(400, "Custom language pack ID must begin with 'X'")); } @@ -1222,23 +1399,25 @@ void LanguagePackManager::set_custom_language(string language_code, string langu CHECK(pack_it != database_->language_packs_.end()); LanguagePack *pack = pack_it->second.get(); auto &info = pack->custom_language_pack_infos_[language_code]; - info.name = std::move(language_name); - info.native_name = std::move(language_native_name); + info = r_info.move_as_ok(); if (!pack->pack_kv_.empty()) { - pack->pack_kv_.set(language_code, PSLICE() << info.name << '\x00' << info.native_name); + pack->pack_kv_.set(language_code, get_language_info_string(info)); } promise.set_value(Unit()); } -void LanguagePackManager::edit_custom_language_info(string language_code, string language_name, - string language_native_name, Promise &&promise) { +void LanguagePackManager::edit_custom_language_info(td_api::object_ptr &&language_pack_info, + Promise &&promise) { if (language_pack_.empty()) { return promise.set_error(Status::Error(400, "Option \"localization_target\" needs to be set first")); } - if (!check_language_code_name(language_code)) { - return promise.set_error(Status::Error(400, "Language pack ID must contain only letters, digits and hyphen")); + + auto r_info = get_language_info(language_pack_info.get()); + if (r_info.is_error()) { + return promise.set_error(r_info.move_as_error()); } + auto language_code = std::move(language_pack_info->id_); if (!is_custom_language_code(language_code)) { return promise.set_error(Status::Error(400, "Custom language pack ID must begin with 'X'")); } @@ -1252,10 +1431,9 @@ void LanguagePackManager::edit_custom_language_info(string language_code, string return promise.set_error(Status::Error(400, "Custom language pack is not found")); } auto &info = language_info_it->second; - info.name = std::move(language_name); - info.native_name = std::move(language_native_name); + info = r_info.move_as_ok(); if (!pack->pack_kv_.empty()) { - pack->pack_kv_.set(language_code, PSLICE() << info.name << '\x00' << info.native_name); + pack->pack_kv_.set(language_code, get_language_info_string(info)); } promise.set_value(Unit()); @@ -1349,12 +1527,10 @@ Status LanguagePackManager::do_delete_language(string language_code) { language->pluralized_strings_.clear(); language->deleted_strings_.clear(); - if (is_custom_language_code(language_code)) { - if (!pack->pack_kv_.empty()) { - pack->pack_kv_.erase(language_code); - } - pack->custom_language_pack_infos_.erase(language_code); + if (!pack->pack_kv_.empty()) { + pack->pack_kv_.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 5456828a8..dd7e58e87 100644 --- a/td/telegram/LanguagePackManager.h +++ b/td/telegram/LanguagePackManager.h @@ -61,10 +61,10 @@ class LanguagePackManager : public NetQueryCallback { void on_update_language_pack(tl_object_ptr difference); - void set_custom_language(string language_code, string language_name, string language_native_name, + void set_custom_language(td_api::object_ptr &&language_pack_info, vector> strings, Promise &&promise); - void edit_custom_language_info(string language_code, string language_name, string language_native_name, + void edit_custom_language_info(td_api::object_ptr &&language_pack_info, Promise &&promise); void set_custom_language_string(string language_code, tl_object_ptr str, @@ -130,6 +130,13 @@ class LanguagePackManager : public NetQueryCallback { static td_api::object_ptr get_language_pack_strings_object(Language *language, const vector &keys); + static td_api::object_ptr get_language_pack_info_object(const string &language_code, + const LanguageInfo &info); + + static Result get_language_info(td_api::languagePackInfo *language_pack_info); + + static string get_language_info_string(const LanguageInfo &info); + static Result> convert_to_telegram_api( tl_object_ptr &&str); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index ad9e78617..6746d8d90 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6196,29 +6196,16 @@ void Td::on_request(uint64 id, td_api::getLanguagePackStrings &request) { void Td::on_request(uint64 id, td_api::setCustomLanguagePack &request) { CHECK_IS_USER(); - if (request.info_ == nullptr) { - return send_error_raw(id, 400, "Language pack info must not be empty"); - } - CLEAN_INPUT_STRING(request.info_->id_); - CLEAN_INPUT_STRING(request.info_->name_); - CLEAN_INPUT_STRING(request.info_->native_name_); CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::set_custom_language, std::move(request.info_->id_), - std::move(request.info_->name_), std::move(request.info_->native_name_), std::move(request.strings_), - std::move(promise)); + send_closure(language_pack_manager_, &LanguagePackManager::set_custom_language, std::move(request.info_), + std::move(request.strings_), std::move(promise)); } void Td::on_request(uint64 id, td_api::editCustomLanguagePackInfo &request) { CHECK_IS_USER(); - if (request.info_ == nullptr) { - return send_error_raw(id, 400, "Language pack info must not be empty"); - } - CLEAN_INPUT_STRING(request.info_->id_); - CLEAN_INPUT_STRING(request.info_->name_); - CLEAN_INPUT_STRING(request.info_->native_name_); CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::edit_custom_language_info, std::move(request.info_->id_), - std::move(request.info_->name_), std::move(request.info_->native_name_), std::move(promise)); + send_closure(language_pack_manager_, &LanguagePackManager::edit_custom_language_info, std::move(request.info_), + std::move(promise)); } void Td::on_request(uint64 id, td_api::setCustomLanguagePackString &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index c214598f6..b509b124f 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -485,7 +485,7 @@ class CliClient final : public Actor { return transform(full_split(user_ids, delimiter), [this](Slice str) { return as_user_id(str); }); } - int32 as_basic_group_id(Slice str) const { + static int32 as_basic_group_id(Slice str) { str = trim(str); auto result = to_integer(str); if (result < 0) { @@ -494,7 +494,7 @@ class CliClient final : public Actor { return result; } - int32 as_supergroup_id(Slice str) const { + static int32 as_supergroup_id(Slice str) { str = trim(str); auto result = to_integer(str); int64 shift = static_cast(-1000000000000ll); @@ -504,7 +504,7 @@ class CliClient final : public Actor { return static_cast(result); } - int32 as_secret_chat_id(Slice str) const { + static int32 as_secret_chat_id(Slice str) { str = trim(str); auto result = to_integer(str); int64 shift = static_cast(-2000000000000ll); @@ -882,7 +882,7 @@ class CliClient final : public Actor { return as_formatted_text(caption, std::move(entities)); } - tl_object_ptr get_notification_settings_scope(Slice scope) const { + static tl_object_ptr get_notification_settings_scope(Slice scope) { if (scope == "channels" || scope == "ch") { return make_tl_object(); } @@ -988,7 +988,7 @@ class CliClient final : public Actor { return nullptr; } - tl_object_ptr get_top_chat_category(MutableSlice category) { + static tl_object_ptr get_top_chat_category(MutableSlice category) { category = trim(category); to_lower_inplace(category); if (!category.empty() && category.back() == 's') { @@ -1177,6 +1177,13 @@ class CliClient final : public Actor { return nullptr; } + static td_api::object_ptr as_language_pack_info(const string &language_code, + const string &name, + const string &native_name) { + return td_api::make_object(language_code, "test", name, native_name, "en", true, true, + true, -1, 5, 3, "abacaba"); + } + static td_api::object_ptr execute(tl_object_ptr f) { if (GET_VERBOSITY_LEVEL() < VERBOSITY_NAME(td_requests)) { LOG(ERROR) << "Execute request: " << to_string(f); @@ -1859,7 +1866,7 @@ class CliClient final : public Actor { "DELETED", make_tl_object())); send_request(make_tl_object( - make_tl_object(language_code, name, native_name, 3), std::move(strings))); + as_language_pack_info(language_code, name, native_name), std::move(strings))); } else if (op == "eclpi") { string language_code; string name; @@ -1868,8 +1875,8 @@ class CliClient final : public Actor { std::tie(language_code, args) = split(args); std::tie(name, native_name) = split(args); - send_request(make_tl_object( - make_tl_object(language_code, name, native_name, 3))); + send_request( + make_tl_object(as_language_pack_info(language_code, name, native_name))); } else if (op == "sclpsv" || op == "sclpsp" || op == "sclpsd") { string language_code; string key;