Browse Source

Add `string::translate()` and `settings::language` for getting translated strings depending on language.

tags/v2.6.1
Andrew Belt 5 months ago
parent
commit
89aede6e9e
6 changed files with 92 additions and 0 deletions
  1. +1
    -0
      adapters/standalone.cpp
  2. +2
    -0
      include/settings.hpp
  3. +5
    -0
      include/string.hpp
  4. +7
    -0
      src/settings.cpp
  5. +74
    -0
      src/string.cpp
  6. +3
    -0
      translations/en.json

+ 1
- 0
adapters/standalone.cpp View File

@@ -179,6 +179,7 @@ int main(int argc, char* argv[]) {
exit(1);
}
}
string::init();

// Check existence of the system res/ directory
std::string resDir = asset::system("res");


+ 2
- 0
include/settings.hpp View File

@@ -27,6 +27,8 @@ extern bool isPlugin;

// Persistent state, serialized to settings.json.

/** ISO 639-1 language code for string translations. */
extern std::string language;
/** Launches Rack without loading plugins or the autosave patch. Always set to false when settings are saved. */
extern bool safeMode;
/** vcvrack.com user token */


+ 5
- 0
include/string.hpp View File

@@ -131,5 +131,10 @@ struct Version {
};


std::string translate(const std::string& id);
std::string translate(const std::string& id, const std::string& language);
void init();


} // namespace string
} // namespace rack

+ 7
- 0
src/settings.cpp View File

@@ -20,6 +20,7 @@ bool devMode = false;
bool headless = false;
bool isPlugin = false;

std::string language = "en";
bool safeMode = false;
std::string token;
bool windowMaximized = false;
@@ -126,6 +127,8 @@ void destroy() {
json_t* toJson() {
json_t* rootJ = json_object();

json_object_set_new(rootJ, "language", json_string(language.c_str()));

// Always disable safe mode when settings are saved.
json_object_set_new(rootJ, "safeMode", json_boolean(false));

@@ -281,6 +284,10 @@ json_t* toJson() {
}

void fromJson(json_t* rootJ) {
json_t* languageJ = json_object_get(rootJ, "language");
if (languageJ)
language = json_string_value(languageJ);

json_t* safeModeJ = json_object_get(rootJ, "safeMode");
if (safeModeJ) {
// If safe mode is enabled (e.g. by command line flag), don't disable it when loading.


+ 74
- 0
src/string.cpp View File

@@ -3,6 +3,7 @@
#include <ctime>
#include <cctype> // for tolower and toupper
#include <algorithm> // for transform and equal
#include <map>
#include <libgen.h> // for dirname and basename
#include <stdarg.h>

@@ -11,6 +12,9 @@
#endif

#include <string.hpp>
#include <settings.hpp>
#include <system.hpp>
#include <asset.hpp>


namespace rack {
@@ -322,6 +326,76 @@ bool Version::operator<(const Version& other) {
}


/** {language: {id: string}} */
static std::map<std::string, std::map<std::string, std::string>> translations;


static void loadTranslations() {
translations.clear();
std::string translationsDir = asset::system("translations");

for (std::string filename : system::getEntries(translationsDir)) {
if (system::getExtension(filename) != ".json")
continue;
std::string language = system::getStem(filename);
std::string path = system::join(translationsDir, filename);

INFO("Loading translation %s from %s", language.c_str(), path.c_str());
FILE* file = std::fopen(path.c_str(), "r");
if (!file) {
WARN("Cannot open translation file %s", path.c_str());
continue;
}
DEFER({std::fclose(file);});

json_error_t error;
json_t* rootJ = json_loadf(file, 0, &error);
if (!rootJ) {
WARN("Translation file has invalid JSON at %d:%d %s", error.line, error.column, error.text);
continue;
}
DEFER({json_decref(rootJ);});

auto& translation = translations[language];

// Load JSON
const char* id;
json_t* strJ;
json_object_foreach(rootJ, id, strJ) {
std::string s(json_string_value(strJ), json_string_length(strJ));
translation[id] = s;
}
}
}


std::string translate(const std::string& id) {
std::string s = translate(id, settings::language);
if (!s.empty())
return s;

// English fallback
if (settings::language != "en") {
return translate(id, "en");
}
return "";
}


std::string translate(const std::string& id, const std::string& language) {
auto it = translations.find(language);
if (it == translations.end())
return "";

const auto& translation = it->second;
return get(translation, id, "");
}


void init() {
loadTranslations();
}


} // namespace string
} // namespace rack

+ 3
- 0
translations/en.json View File

@@ -0,0 +1,3 @@
{
"language": "English"
}

Loading…
Cancel
Save