Skip to content

Commit

Permalink
Addon titles and descriptions made translatable
Browse files Browse the repository at this point in the history
Modified the `translation` tag in the addon structure and made the translated names shown in the corresponding locale on the client side.

See the related pull-request for more information.
  • Loading branch information
kabachuha authored and irydacea committed Jul 9, 2020
1 parent 9636958 commit 10e75e6
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/addon/client.cpp
Expand Up @@ -308,7 +308,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();
Expand Down
87 changes: 84 additions & 3 deletions src/addon/info.cpp
Expand Up @@ -18,6 +18,7 @@
#include "config.hpp"
#include "font/pango/escape.hpp"
#include "gettext.hpp"
#include "language.hpp"
#include "picture.hpp"
#include "log.hpp"
#include "serialization/string_utils.hpp"
Expand Down Expand Up @@ -57,6 +58,22 @@ namespace {
}
}

void addon_info_translation::read(const config& cfg)
{
this->language = cfg["language"].str();
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["language"] = this->language;
cfg["supported"] = this->supported;
cfg["title"] = this->title;
cfg["description"] = this->description;
}

void addon_info::read(const config& cfg)
{
this->id = cfg["name"].str();
Expand All @@ -73,7 +90,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.push_back(locale["language"].str());
this->info_translations.push_back(addon_info_translation(locale));
}

this->core = cfg["core"].str();
Expand All @@ -100,8 +119,8 @@ 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 addon_info_translation& locale : this->info_translations) {
locale.write(cfg.add_child("translation"));
}

cfg["core"] = this->core;
Expand Down Expand Up @@ -132,6 +151,68 @@ std::string addon_info::display_title() const
}
}

addon_info_translation addon_info_translation::invalid = {"en_US", false, "invalid_addon!", ""};

addon_info_translation addon_info::translated_info() const
{
std::string locale = get_language().localename;

if(locale != "en_US") {
for(const addon_info_translation& info : this->info_translations) {
if(info.language == locale || info.language == locale.substr(0, 2)) {
return info;
}
}
}

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()) {
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_title_full_shift() const
{
std::string local_title = display_title_translated();
if(local_title.empty())
return display_title();
return local_title + "\n"
+ "<small>(" + display_title() + ")</small>";
}

std::string addon_info::display_icon() const
{
std::string ret = icon;
Expand Down
74 changes: 74 additions & 0 deletions src/addon/info.hpp
Expand Up @@ -22,10 +22,67 @@
#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;

std::string language;
bool supported;
std::string title;
std::string description;

addon_info_translation()
: language()
, supported(true)
, title()
, description()
{}

addon_info_translation(std::string lang, bool sup, std::string titl, std::string desc)
: language(lang)
, supported(sup)
, title(titl)
, description(desc)
{
}

explicit addon_info_translation(const config& cfg)
: language()
, 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->language = o.language;
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 != "invalid_addon!";
}
};

struct addon_info
{
std::string id;
Expand Down Expand Up @@ -61,6 +118,8 @@ struct addon_info
// not previously published.
bool local_only;

std::vector<addon_info_translation> info_translations;

addon_info()
: id(), title(), description(), icon()
, version(), author(), size(), downloads()
Expand All @@ -71,6 +130,7 @@ struct addon_info
, updated()
, created()
, local_only(false)
, info_translations()
{}

explicit addon_info(const config& cfg)
Expand All @@ -83,6 +143,7 @@ struct addon_info
, updated()
, created()
, local_only(false)
, info_translations()
{
this->read(cfg);
}
Expand All @@ -109,6 +170,7 @@ struct addon_info
this->updated = o.updated;
this->created = o.created;
this->local_only = o.local_only;
this->info_translations = o.info_translations;
}
return *this;
}
Expand Down Expand Up @@ -138,6 +200,18 @@ 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 display_title_full_shift() 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;

Expand Down
24 changes: 22 additions & 2 deletions src/campaign_server/addon_utils.cpp
Expand Up @@ -92,23 +92,43 @@ std::string format_addon_feedback_url(const std::string& format, const config& p
return std::string();
}

void support_translation(config& addon, std::string locale_id)
{
if(!locale_id.empty()) {
config& locale = addon.find_child("translation", "language", locale_id);
if(locale) {
locale["supported"] = true;
}
else {
addon.add_child("translation")["language"] = locale_id; //Doing this to circumvent a weird validation bug
addon.find_child("translation", "language", locale_id)["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);
}
}

for(config& locale : addon.child_range("translation")) {
if(!locale["supported"].to_bool(false)) {
locale["supported"] = false;
}
}
}

void add_license(config& cfg)
Expand Down
1 change: 1 addition & 0 deletions src/campaign_server/addon_utils.hpp
Expand Up @@ -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, std::string locale_id);

/**
* Scans an add-on archive directory for translations.
Expand Down
12 changes: 10 additions & 2 deletions src/campaign_server/campaign_server.cpp
Expand Up @@ -623,7 +623,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)) {
found = true;
break;
}
Expand Down Expand Up @@ -881,6 +881,11 @@ 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")) {
(*campaign).add_child("translation", locale_params);
}

const std::string& filename = (*campaign)["filename"].str();
data["title"] = (*campaign)["title"];
data["name"] = "";
Expand All @@ -893,9 +898,12 @@ 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);

for(const config& locale_params : (*campaign).child_range("translation")) {
data.add_child("translation", locale_params);//Do we need it?
}

add_license(data);

{
Expand Down

0 comments on commit 10e75e6

Please sign in to comment.