Addon titles and descriptions made translatable
Backport of https://github.com/wesnoth/wesnoth/pull/4984 to 1.14
This commit is contained in:
parent
38736e757e
commit
8cb7139a81
10 changed files with 213 additions and 19 deletions
|
@ -1099,6 +1099,9 @@
|
|||
[entry]
|
||||
name = "Anja Keicher (ayne)"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Artem Khrapov (kabachuha)"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Astrid Halberkamp (bumbadadabum)"
|
||||
[/entry]
|
||||
|
|
|
@ -312,7 +312,7 @@ bool addons_client::try_fetch_addon(const addon_info & addon)
|
|||
config archive;
|
||||
|
||||
if(!(
|
||||
download_addon(archive, addon.id, addon.title, !is_addon_installed(addon.id)) &&
|
||||
download_addon(archive, addon.id, addon.display_title_full(), !is_addon_installed(addon.id)) &&
|
||||
install_addon(archive, addon)
|
||||
)) {
|
||||
const std::string& server_error = get_last_server_error();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "font/pango/escape.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "language.hpp"
|
||||
#include "picture.hpp"
|
||||
#include "log.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
@ -58,6 +59,20 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
void addon_info_translation::read(const config& cfg)
|
||||
{
|
||||
this->supported = cfg["supported"].to_bool(true);
|
||||
this->title = cfg["title"].str();
|
||||
this->description = cfg["description"].str();
|
||||
}
|
||||
|
||||
void addon_info_translation::write(config& cfg) const
|
||||
{
|
||||
cfg["supported"] = this->supported;
|
||||
cfg["title"] = this->title;
|
||||
cfg["description"] = this->description;
|
||||
}
|
||||
|
||||
void addon_info::read(const config& cfg)
|
||||
{
|
||||
this->id = cfg["name"].str();
|
||||
|
@ -74,7 +89,9 @@ void addon_info::read(const config& cfg)
|
|||
const config::const_child_itors& locales_as_configs = cfg.child_range("translation");
|
||||
|
||||
for(const config& locale : locales_as_configs) {
|
||||
this->locales.push_back(locale["language"].str());
|
||||
if(locale["supported"].to_bool(true))
|
||||
this->locales.emplace_back(locale["language"].str());
|
||||
this->info_translations.emplace(locale["language"].str(), addon_info_translation(locale));
|
||||
}
|
||||
|
||||
this->core = cfg["core"].str();
|
||||
|
@ -101,8 +118,10 @@ void addon_info::write(config& cfg) const
|
|||
cfg["uploads"] = this->uploads;
|
||||
cfg["type"] = get_addon_type_string(this->type);
|
||||
|
||||
for (const std::string& locale_id : this->locales) {
|
||||
cfg.add_child("translation")["language"] = locale_id;
|
||||
for(const auto& element : this->info_translations) {
|
||||
config& locale = cfg.add_child("translation");
|
||||
locale["language"] = element.first;
|
||||
element.second.write(locale);
|
||||
}
|
||||
|
||||
cfg["core"] = this->core;
|
||||
|
@ -133,6 +152,63 @@ std::string addon_info::display_title() const
|
|||
}
|
||||
}
|
||||
|
||||
addon_info_translation addon_info_translation::invalid = {false, "", ""};
|
||||
|
||||
addon_info_translation addon_info::translated_info() const
|
||||
{
|
||||
std::string locale = get_language().localename;
|
||||
|
||||
if(locale != "en_US") {
|
||||
auto info = info_translations.find(locale);
|
||||
if(info != info_translations.end()) {
|
||||
return info->second;
|
||||
}
|
||||
|
||||
info = info_translations.find(locale.substr(0, 2));
|
||||
if(info != info_translations.end()) {
|
||||
return info->second;
|
||||
}
|
||||
}
|
||||
|
||||
return addon_info_translation::invalid;
|
||||
}
|
||||
|
||||
std::string addon_info::display_title_translated() const
|
||||
{
|
||||
addon_info_translation info = this->translated_info();
|
||||
|
||||
if(info.valid()) {
|
||||
return info.title;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string addon_info::display_title_translated_or_original() const
|
||||
{
|
||||
std::string title = display_title_translated();
|
||||
return title.empty() ? display_title() : title;
|
||||
}
|
||||
|
||||
std::string addon_info::description_translated() const
|
||||
{
|
||||
addon_info_translation info = this->translated_info();
|
||||
|
||||
if(info.valid() && !info.description.empty()) {
|
||||
return info.description;
|
||||
}
|
||||
|
||||
return this->description;
|
||||
}
|
||||
|
||||
std::string addon_info::display_title_full() const
|
||||
{
|
||||
std::string local_title = display_title_translated();
|
||||
if(local_title.empty())
|
||||
return display_title();
|
||||
return local_title + " (" + display_title() + ")";
|
||||
}
|
||||
|
||||
std::string addon_info::display_icon() const
|
||||
{
|
||||
std::string ret = icon;
|
||||
|
|
|
@ -22,10 +22,63 @@
|
|||
#include <set>
|
||||
#include <map>
|
||||
|
||||
struct addon_info_translation;
|
||||
struct addon_info;
|
||||
class config;
|
||||
typedef std::map<std::string, addon_info> addons_list;
|
||||
|
||||
struct addon_info_translation
|
||||
{
|
||||
static addon_info_translation invalid;
|
||||
|
||||
bool supported;
|
||||
std::string title;
|
||||
std::string description;
|
||||
|
||||
addon_info_translation()
|
||||
: supported(true)
|
||||
, title()
|
||||
, description()
|
||||
{
|
||||
}
|
||||
|
||||
addon_info_translation(bool sup, std::string titl, std::string desc)
|
||||
: supported(sup)
|
||||
, title(titl)
|
||||
, description(desc)
|
||||
{
|
||||
}
|
||||
|
||||
explicit addon_info_translation(const config& cfg)
|
||||
: supported(true)
|
||||
, title()
|
||||
, description()
|
||||
{
|
||||
this->read(cfg);
|
||||
}
|
||||
|
||||
addon_info_translation(const addon_info_translation&) = default;
|
||||
|
||||
addon_info_translation& operator=(const addon_info_translation& o)
|
||||
{
|
||||
if(this != &o) {
|
||||
this->supported = o.supported;
|
||||
this->title = o.title;
|
||||
this->description = o.description;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void read(const config& cfg);
|
||||
|
||||
void write(config& cfg) const;
|
||||
|
||||
bool valid()
|
||||
{
|
||||
return !title.empty();
|
||||
}
|
||||
};
|
||||
|
||||
struct addon_info
|
||||
{
|
||||
std::string id;
|
||||
|
@ -66,6 +119,8 @@ struct addon_info
|
|||
// not previously published.
|
||||
bool local_only;
|
||||
|
||||
std::map<std::string, addon_info_translation> info_translations;
|
||||
|
||||
addon_info()
|
||||
: id(), title(), description(), icon()
|
||||
, version(), author(), size(), downloads()
|
||||
|
@ -77,6 +132,7 @@ struct addon_info
|
|||
, created()
|
||||
, order()
|
||||
, local_only(false)
|
||||
, info_translations()
|
||||
{}
|
||||
|
||||
explicit addon_info(const config& cfg)
|
||||
|
@ -90,6 +146,7 @@ struct addon_info
|
|||
, created()
|
||||
, order()
|
||||
, local_only(false)
|
||||
, info_translations()
|
||||
{
|
||||
this->read(cfg);
|
||||
}
|
||||
|
@ -115,6 +172,7 @@ struct addon_info
|
|||
this->created = o.created;
|
||||
this->order = o.order;
|
||||
this->local_only = o.local_only;
|
||||
this->info_translations = o.info_translations;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -144,6 +202,16 @@ struct addon_info
|
|||
*/
|
||||
std::string display_title() const;
|
||||
|
||||
addon_info_translation translated_info() const;
|
||||
|
||||
std::string display_title_translated() const;
|
||||
|
||||
std::string display_title_translated_or_original() const;
|
||||
|
||||
std::string display_title_full() const;
|
||||
|
||||
std::string description_translated() const;
|
||||
|
||||
/** Get an icon path fixed for display (e.g. when TC is missing, or the image doesn't exist). */
|
||||
std::string display_icon() const;
|
||||
|
||||
|
|
|
@ -92,19 +92,29 @@ std::string format_addon_feedback_url(const std::string& format, const config& p
|
|||
return std::string();
|
||||
}
|
||||
|
||||
void support_translation(config& addon, const std::string& locale_id)
|
||||
{
|
||||
config* locale = &addon.find_child("translation", "language", locale_id);
|
||||
if(!*locale) {
|
||||
locale = &addon.add_child("translation");
|
||||
(*locale)["language"] = locale_id;
|
||||
}
|
||||
(*locale)["supported"] = true;
|
||||
}
|
||||
|
||||
void find_translations(const config& base_dir, config& addon)
|
||||
{
|
||||
for(const config& file : base_dir.child_range("file")) {
|
||||
const std::string& fn = file["name"].str();
|
||||
if(filesystem::ends_with(fn, ".po")) {
|
||||
addon.add_child("translation")["language"] = filesystem::base_name(fn, true);
|
||||
support_translation(addon, filesystem::base_name(fn, true));
|
||||
}
|
||||
}
|
||||
|
||||
for(const config &dir : base_dir.child_range("dir"))
|
||||
{
|
||||
if(dir["name"] == "LC_MESSAGES") {
|
||||
addon.add_child("translation")["language"] = base_dir["name"];
|
||||
support_translation(addon, base_dir["name"]);
|
||||
} else {
|
||||
find_translations(dir, addon);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ inline bool is_text_markup_char(char c)
|
|||
*/
|
||||
std::string format_addon_feedback_url(const std::string& format, const config& params);
|
||||
|
||||
void support_translation(config& addon, const std::string& locale_id);
|
||||
|
||||
/**
|
||||
* Scans an add-on archive directory for translations.
|
||||
|
|
|
@ -625,7 +625,7 @@ void server::handle_request_campaign_list(const server::request& req)
|
|||
|
||||
for(const config& j : i.child_range("translation"))
|
||||
{
|
||||
if(j["language"] == lang) {
|
||||
if(j["language"] == lang && j["supported"].to_bool(true)) { // for old addons
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -886,6 +886,22 @@ void server::handle_upload(const server::request& req)
|
|||
(*campaign).add_child("feedback", url_params);
|
||||
}
|
||||
|
||||
(*campaign).clear_children("translation");
|
||||
for(const config& locale_params : upload.child_range("translation")) {
|
||||
if(!locale_params["language"].empty()) {
|
||||
config& locale = (*campaign).add_child("translation");
|
||||
locale["language"] = locale_params["language"].str();
|
||||
locale["supported"] = false;
|
||||
|
||||
if(!locale_params["title"].empty()) {
|
||||
locale["title"] = locale_params["title"].str();
|
||||
}
|
||||
if(!locale_params["description"].empty()) {
|
||||
locale["description"] = locale_params["description"].str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& filename = (*campaign)["filename"].str();
|
||||
data["title"] = (*campaign)["title"];
|
||||
data["name"] = "";
|
||||
|
@ -898,7 +914,6 @@ void server::handle_upload(const server::request& req)
|
|||
data["icon"] = (*campaign)["icon"];
|
||||
data["type"] = (*campaign)["type"];
|
||||
data["tags"] = (*campaign)["tags"];
|
||||
(*campaign).clear_children("translation");
|
||||
find_translations(data, *campaign);
|
||||
|
||||
add_license(data);
|
||||
|
|
|
@ -118,6 +118,15 @@ namespace {
|
|||
break;
|
||||
}
|
||||
}
|
||||
for(const config& child : cfg.child_range("translation")) {
|
||||
for(const auto& attribute : child.attribute_range()) {
|
||||
std::string val = attribute.second.str();
|
||||
if(translation::ci_search(val, filter)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
return false;
|
||||
}
|
||||
|
@ -160,7 +169,7 @@ namespace {
|
|||
str += ", ";
|
||||
}
|
||||
|
||||
str += addon_list::colorize_addon_state_string(dep.display_title(), depstate.state);
|
||||
str += addon_list::colorize_addon_state_string(dep.display_title_translated_or_original(), depstate.state);
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -673,14 +682,14 @@ void addon_manager::uninstall_addon(const addon_info& addon, window& window)
|
|||
if(have_addon_pbl_info(addon.id) || have_addon_in_vcs_tree(addon.id)) {
|
||||
show_error_message(
|
||||
_("The following add-on appears to have publishing or version control information stored locally, and will not be removed:") + " " +
|
||||
addon.display_title());
|
||||
addon.display_title_full());
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = remove_local_addon(addon.id);
|
||||
|
||||
if(!success) {
|
||||
gui2::show_error_message(_("The following add-on could not be deleted properly:") + " " + addon.display_title());
|
||||
gui2::show_error_message(_("The following add-on could not be deleted properly:") + " " + addon.display_title_full());
|
||||
} else {
|
||||
need_wml_cache_refresh_ = true;
|
||||
|
||||
|
@ -806,7 +815,7 @@ void addon_manager::execute_default_action(const addon_info& addon, window& wind
|
|||
break;
|
||||
case ADDON_INSTALLED:
|
||||
if(!tracking_info_[addon.id].can_publish) {
|
||||
utils::string_map symbols{ { "addon", addon.display_title() } };
|
||||
utils::string_map symbols{ { "addon", addon.display_title_full() } };
|
||||
int res = gui2::show_message(_("Uninstall add-on"),
|
||||
VGETTEXT("Do you want to uninstall '$addon|'?", symbols),
|
||||
gui2::dialogs::message::ok_cancel_buttons);
|
||||
|
@ -875,8 +884,8 @@ void addon_manager::on_addon_select(window& window)
|
|||
|
||||
find_widget<drawing>(parent, "image", false).set_label(info->display_icon());
|
||||
|
||||
find_widget<styled_widget>(parent, "title", false).set_label(info->display_title());
|
||||
find_widget<styled_widget>(parent, "description", false).set_label(info->description);
|
||||
find_widget<styled_widget>(parent, "title", false).set_label(info->display_title_translated_or_original());
|
||||
find_widget<styled_widget>(parent, "description", false).set_label(info->description_translated());
|
||||
find_widget<styled_widget>(parent, "version", false).set_label(info->version.str());
|
||||
find_widget<styled_widget>(parent, "author", false).set_label(info->author);
|
||||
find_widget<styled_widget>(parent, "type", false).set_label(info->display_type());
|
||||
|
|
|
@ -144,6 +144,16 @@ void addon_list::addon_action_wrapper(addon_op_func_t& func, const addon_info& a
|
|||
}
|
||||
}
|
||||
|
||||
const std::string addon_list::display_title_full_shift(const addon_info& addon) const
|
||||
{
|
||||
const std::string& local_title = addon.display_title_translated();
|
||||
const std::string& display_title = addon.display_title();
|
||||
if(local_title.empty())
|
||||
return display_title;
|
||||
return local_title + "\n"
|
||||
+ "<small>(" + display_title + ")</small>";
|
||||
}
|
||||
|
||||
void addon_list::set_addons(const addons_list& addons)
|
||||
{
|
||||
listbox& list = get_listbox();
|
||||
|
@ -164,7 +174,7 @@ void addon_list::set_addons(const addons_list& addons)
|
|||
item["label"] = addon.display_icon();
|
||||
data.emplace("icon", item);
|
||||
|
||||
item["label"] = addon.display_title();
|
||||
item["label"] = display_title_full_shift(addon);
|
||||
data.emplace("name", item);
|
||||
} else {
|
||||
item["label"] = addon.display_icon() + "~SCALE(72,72)~BLIT(icons/icon-addon-publish.png,8,8)";
|
||||
|
@ -172,7 +182,7 @@ void addon_list::set_addons(const addons_list& addons)
|
|||
|
||||
const std::string publish_name = formatter()
|
||||
<< font::span_color(font::GOOD_COLOR)
|
||||
<< addon.display_title()
|
||||
<< display_title_full_shift(addon)
|
||||
<< "</span>";
|
||||
|
||||
item["label"] = publish_name;
|
||||
|
@ -347,7 +357,7 @@ void addon_list::select_addon(const std::string& id)
|
|||
grid* row = list.get_row_grid(i);
|
||||
|
||||
const label& name_label = find_widget<label>(row, "name", false);
|
||||
if(name_label.get_label().base_str() == info.display_title()) {
|
||||
if(name_label.get_label().base_str() == display_title_full_shift(info)) {
|
||||
list.select_row(i);
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +379,7 @@ void addon_list::finalize_setup()
|
|||
{
|
||||
listbox& list = get_listbox();
|
||||
|
||||
list.register_translatable_sorting_option(0, [this](const int i) { return addon_vector_[i]->title; });
|
||||
list.register_translatable_sorting_option(0, [this](const int i) { return addon_vector_[i]->display_title_full(); });
|
||||
list.register_sorting_option(1, [this](const int i) { return addon_vector_[i]->author; });
|
||||
list.register_sorting_option(2, [this](const int i) { return addon_vector_[i]->size; });
|
||||
list.register_sorting_option(3, [this](const int i) { return addon_vector_[i]->downloads; });
|
||||
|
@ -402,7 +412,7 @@ void addon_list::select_first_addon()
|
|||
const addon_info* first_addon = addon_vector_[0];
|
||||
|
||||
for(const addon_info* a : addon_vector_) {
|
||||
if(a->display_title().compare(first_addon->display_title()) < 0) {
|
||||
if(translation::icompare(a->display_title_full(), first_addon->display_title_full()) < 0) {
|
||||
first_addon = a;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
/** Special retval for the toggle panels in the addons list */
|
||||
static const int DEFAULT_ACTION_RETVAL = 200;
|
||||
|
||||
const std::string display_title_full_shift(const addon_info& addon) const;
|
||||
|
||||
/** Sets the add-ons to show. */
|
||||
void set_addons(const addons_list& addons);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue