diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c8a90b284..3cd0c63e2 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3133,9 +3133,12 @@ getLanguagePackInfo = LanguagePack; //@description Returns strings from a language in the used language pack by their keys @language_code Language code of strings to return @keys Language pack keys of strings to return; may be empty to get all available strings getLanguagePackStrings language_code:string keys:vector = LanguagePackStrings; -//@description Adds or changes a custom language to the used language pack @info Information about the language. Language code should start with 'X' @strings New language pack strings +//@description Adds or changes a custom language to the used language pack @info Information about the language. Language code must start with 'X' @strings New language pack strings setCustomLanguage info:languageInfo strings:vector = Ok; +//@description Sets new value for a string in a custom language in the used language pack @language_code The code of previously added custom language, must start with 'X' @string New language pack string +setCustomLanguageString language_code:string string:LanguagePackString = Ok; + //@description Deletes all information about a language in the used language pack. Currently used language can't be deleted @language_code Language code of a language to delete deleteLanguage language_code:string = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index c816c30a6..d7ea24417 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index 63b405cc3..bc3e5f6e7 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -656,7 +656,7 @@ void AnimationsManager::remove_saved_animation(const tl_object_ptrfile_manager_->get_file_view(file_id); CHECK(file_view.has_remote_location()); - CHECK(file_view.remote_location().is_document()); + CHECK(file_view.remote_location().is_document()) << file_view.remote_location(); CHECK(!file_view.remote_location().is_web()); td_->create_handler(std::move(promise))->send(file_view.remote_location().as_input_document(), true); diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index def71aa9d..be95e9f10 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -628,7 +628,7 @@ void LanguagePackManager::save_strings_to_database(Language *language, int32 new return; } auto old_version = load_database_language_version(kv); - if (old_version >= new_version && (old_version != -1 || new_version != -1)) { + if (old_version > new_version || (old_version == new_version && strings.empty())) { LOG(DEBUG) << "Language version doesn't increased from " << old_version; return; } @@ -662,7 +662,7 @@ void LanguagePackManager::on_get_language_pack_strings( bool is_version_changed = false; int32 new_database_version = -1; vector> database_strings; - if (language == nullptr || (language->version_ < version || !keys.empty())) { + if (language == nullptr || language->version_ < version || !keys.empty()) { if (language == nullptr) { language = add_language(database_, language_pack, language_code); CHECK(language != nullptr); @@ -792,56 +792,62 @@ void LanguagePackManager::on_failed_get_difference(string language_pack, string } } +Result> LanguagePackManager::convert_to_telegram_api( + tl_object_ptr &&str) { + if (str == nullptr) { + return Status::Error(400, "Language strings must not be null"); + } + + string key; + downcast_call(*str, [&key](auto &value) { key = std::move(value.key_); }); + if (!is_valid_key(key)) { + return Status::Error(400, "Key is invalid"); + } + switch (str->get_id()) { + case td_api::languagePackStringValue::ID: { + auto value = static_cast(str.get()); + if (!clean_input_string(value->value_)) { + return Status::Error(400, "Strings must be encoded in UTF-8"); + } + return make_tl_object(std::move(key), std::move(value->value_)); + } + case td_api::languagePackStringPluralized::ID: { + auto value = static_cast(str.get()); + if (!clean_input_string(value->zero_value_) || !clean_input_string(value->one_value_) || + !clean_input_string(value->two_value_) || !clean_input_string(value->few_value_) || + !clean_input_string(value->many_value_) || !clean_input_string(value->other_value_)) { + return Status::Error(400, "Strings must be encoded in UTF-8"); + } + return make_tl_object( + 31, std::move(key), std::move(value->zero_value_), std::move(value->one_value_), std::move(value->two_value_), + std::move(value->few_value_), std::move(value->many_value_), std::move(value->other_value_)); + } + case td_api::languagePackStringDeleted::ID: + // there is no reason to save deleted strings in a custom language pack to database + return make_tl_object(std::move(key)); + default: + UNREACHABLE(); + return nullptr; + } +} + void LanguagePackManager::set_custom_language(string language_code, string language_name, string language_native_name, vector> strings, Promise &&promise) { - if (!is_custom_language_code(language_code)) { - return promise.set_error(Status::Error(400, "Custom language code must begin with 'X'")); - } if (!check_language_code_name(language_code)) { return promise.set_error(Status::Error(400, "Language code name must contain only letters and hyphen")); } + if (!is_custom_language_code(language_code)) { + return promise.set_error(Status::Error(400, "Custom language code must begin with 'X'")); + } vector> server_strings; for (auto &str : strings) { - if (str == nullptr) { - return promise.set_error(Status::Error(400, "Language strings must not be null")); - } - string key; - downcast_call(*str, [&key](auto &value) { key = std::move(value.key_); }); - if (!is_valid_key(key)) { - return promise.set_error(Status::Error(400, "Key is invalid")); - } - switch (str->get_id()) { - case td_api::languagePackStringValue::ID: { - auto value = static_cast(str.get()); - if (!clean_input_string(value->value_)) { - return promise.set_error(Status::Error(400, "Strings must be encoded in UTF-8")); - } - server_strings.push_back( - make_tl_object(std::move(key), std::move(value->value_))); - break; - } - case td_api::languagePackStringPluralized::ID: { - auto value = static_cast(str.get()); - if (!clean_input_string(value->zero_value_) || !clean_input_string(value->one_value_) || - !clean_input_string(value->two_value_) || !clean_input_string(value->few_value_) || - !clean_input_string(value->many_value_) || !clean_input_string(value->other_value_)) { - return promise.set_error(Status::Error(400, "Strings must be encoded in UTF-8")); - } - server_strings.push_back(make_tl_object( - 31, std::move(key), std::move(value->zero_value_), std::move(value->one_value_), - std::move(value->two_value_), std::move(value->few_value_), std::move(value->many_value_), - std::move(value->other_value_))); - break; - } - case td_api::languagePackStringDeleted::ID: - // there is no reason to save deleted strings in a custom language pack to database - break; - default: - UNREACHABLE(); - break; + auto r_result = convert_to_telegram_api(std::move(str)); + if (r_result.is_error()) { + return promise.set_error(r_result.move_as_error()); } + server_strings.push_back(r_result.move_as_ok()); } // TODO atomic replace @@ -855,11 +861,45 @@ void LanguagePackManager::set_custom_language(string language_code, string langu auto &info = pack->language_infos_[language_code]; info.name = language_name; info.native_name = language_native_name; - pack->pack_kv_.set(language_code, PSLICE() << language_name << '\x00' << language_native_name); + if (!pack->pack_kv_.empty()) { + pack->pack_kv_.set(language_code, PSLICE() << language_name << '\x00' << language_native_name); + } promise.set_value(Unit()); } +void LanguagePackManager::set_custom_language_string(string language_code, + tl_object_ptr str, + Promise &&promise) { + if (!check_language_code_name(language_code)) { + return promise.set_error(Status::Error(400, "Language code name must contain only letters and hyphen")); + } + if (!is_custom_language_code(language_code)) { + return promise.set_error(Status::Error(400, "Custom language code must begin with 'X'")); + } + + if (get_language(database_, language_pack_, language_code) == nullptr) { + return promise.set_error(Status::Error(400, "Custom language not found")); + } + + string key; + if (str != nullptr) { + downcast_call(*str, [&key](auto &value) { key = value.key_; }); + } + + auto r_str = convert_to_telegram_api(std::move(str)); + if (r_str.is_error()) { + return promise.set_error(r_str.move_as_error()); + } + + vector> server_strings; + server_strings.push_back(r_str.move_as_ok()); + + on_get_language_pack_strings(language_pack_, language_code, 1, true, {std::move(key)}, std::move(server_strings), + Auto()); + promise.set_value(Unit()); +} + void LanguagePackManager::delete_language(string language_code, Promise &&promise) { if (!check_language_code_name(language_code)) { return promise.set_error(Status::Error(400, "Language code name is invalid")); diff --git a/td/telegram/LanguagePackManager.h b/td/telegram/LanguagePackManager.h index 83f3bf5a6..262d958bd 100644 --- a/td/telegram/LanguagePackManager.h +++ b/td/telegram/LanguagePackManager.h @@ -60,6 +60,9 @@ class LanguagePackManager : public NetQueryCallback { void set_custom_language(string language_code, string language_name, string language_native_name, vector> strings, Promise &&promise); + void set_custom_language_string(string language_code, tl_object_ptr str, + Promise &&promise); + void delete_language(string language_code, Promise &&promise); private: @@ -105,6 +108,9 @@ class LanguagePackManager : public NetQueryCallback { static td_api::object_ptr get_language_pack_strings_object(Language *language, const vector &keys); + static Result> convert_to_telegram_api( + tl_object_ptr &&str); + void inc_generation(); static bool is_valid_key(Slice key); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 714a940e1..32dce6921 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3268,6 +3268,7 @@ bool Td::is_preauthentication_request(int32 id) { case td_api::getLanguagePackInfo::ID: case td_api::getLanguagePackStrings::ID: case td_api::setCustomLanguage::ID: + case td_api::setCustomLanguageString::ID: case td_api::deleteLanguage::ID: case td_api::getOption::ID: case td_api::setOption::ID: @@ -6053,6 +6054,14 @@ void Td::on_request(uint64 id, td_api::setCustomLanguage &request) { std::move(promise)); } +void Td::on_request(uint64 id, td_api::setCustomLanguageString &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_code_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(language_pack_manager_, &LanguagePackManager::set_custom_language_string, + std::move(request.language_code_), std::move(request.string_), std::move(promise)); +} + void Td::on_request(uint64 id, td_api::deleteLanguage &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.language_code_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index de4c699bd..6efec72bb 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -769,6 +769,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::setCustomLanguage &request); + void on_request(uint64 id, td_api::setCustomLanguageString &request); + void on_request(uint64 id, td_api::deleteLanguage &request); void on_request(uint64 id, td_api::getOption &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 70dde59f6..992afd885 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1786,6 +1786,25 @@ class CliClient final : public Actor { send_request(make_tl_object( make_tl_object(language_code, name, native_name), std::move(strings))); + } else if (op == "sclsv" || op == "sclsp" || op == "sclsd") { + string language_code; + string key; + string value; + + std::tie(language_code, args) = split(args); + std::tie(key, value) = split(args); + + tl_object_ptr str; + if (op == "sclsv") { + str = make_tl_object(key, value); + } else if (op == "sclsp") { + str = make_tl_object(key, value, string("One\0One", 7), "Two", "Few", + "Many", "Other"); + } else { + str = make_tl_object(key); + } + + send_request(make_tl_object(language_code, std::move(str))); } else if (op == "dl") { send_request(make_tl_object(args)); } else if (op == "go") {