Browse Source

Move English from most app classes to translation file. Add translated names for getKeyName() and getKeyCommandName().

tags/v2.6.1
Andrew Belt 5 months ago
parent
commit
804bd47bc6
8 changed files with 181 additions and 76 deletions
  1. +11
    -0
      include/widget/event.hpp
  2. +26
    -23
      src/app/Browser.cpp
  3. +1
    -1
      src/app/MenuBar.cpp
  4. +5
    -5
      src/app/ParamWidget.cpp
  5. +12
    -12
      src/app/PortWidget.cpp
  6. +15
    -15
      src/plugin/Model.cpp
  7. +30
    -19
      src/widget/event.cpp
  8. +81
    -1
      translations/en.json

+ 11
- 0
include/widget/event.hpp View File

@@ -43,7 +43,18 @@ namespace widget {
struct Widget;


/** Returns the name of a GLFW key macro.
Printable keys return the key string such as "Q", "=", "\t", etc.
Letters are capitalized.
Does not remap keys based on keyboard layout, so GLFW_KEY_Q always returns "Q".
GLFW_KEY_SPACE returns "Space" translated to the current language.
Non-printable characters return the name of the key in the current language.
Key 0 returns "".
*/
std::string getKeyName(int key);
/** Returns the name of a key command/chord/combo.
For example, getKeyCommandName(GLFW_KEY_Q, GLFW_MOD_CONTROL) == "Ctrl+Q" translated to the current language.
*/
std::string getKeyCommandName(int key, int mods = 0);




+ 26
- 23
src/app/Browser.cpp View File

@@ -82,7 +82,7 @@ static ModuleWidget* chooseModel(plugin::Model* model) {
mi.lastAdded = system::getUnixTime();

history::ComplexAction* h = new history::ComplexAction;
h->name = "add module";
h->name = string::translate("Browser.history.addModule");

// Create Module and ModuleWidget
INFO("Creating module %s", model->getFullName().c_str());
@@ -306,7 +306,8 @@ struct ModelBox : widget::OpaqueWidget {
text += "\n" + model->description;
}
// Tags
text += "\n\nTags: ";
text += "\n\n";
text += string::translate("Browser.tooltipTags");
std::vector<std::string> tags;
for (int tagId : model->tagIds) {
tags.push_back(tag::getTag(tagId));
@@ -411,13 +412,15 @@ struct TagButton : ui::ChoiceButton {
};


static const std::string sortNames[] = {
"Last updated",
"Last used",
"Most used",
"Brand",
"Module name",
"Random",
static std::vector<std::string> getSortNames() {
return {
string::translate("Browser.sort.lastUpdated"),
string::translate("Browser.sort.lastUsed"),
string::translate("Browser.sort.mostUsed"),
string::translate("Browser.sort.brand"),
string::translate("Browser.sort.moduleName"),
string::translate("Browser.sort.random"),
};
};


@@ -427,8 +430,8 @@ struct SortButton : ui::ChoiceButton {
void onAction(const ActionEvent& e) override;

void step() override {
text = "Sort: ";
text += sortNames[settings::browserSort];
text = string::translate("Browser.sort");
text += getSortNames()[settings::browserSort];
ChoiceButton::step();
}
};
@@ -440,7 +443,7 @@ struct ZoomButton : ui::ChoiceButton {
void onAction(const ActionEvent& e) override;

void step() override {
text = "Zoom: ";
text = string::translate("Browser.zoom");
text += string::f("%.0f%%", std::pow(2.f, settings::browserZoom) * 100.f);
ChoiceButton::step();
}
@@ -492,7 +495,7 @@ struct Browser : widget::OpaqueWidget {

searchField = new BrowserSearchField;
searchField->box.size.x = 150;
searchField->placeholder = "Search modules";
searchField->placeholder = string::translate("Browser.searchModules");
searchField->browser = this;
headerLayout->addChild(searchField);

@@ -511,13 +514,13 @@ struct Browser : widget::OpaqueWidget {

favoriteButton = new ui::OptionButton;
favoriteButton->quantity = favoriteQuantity;
favoriteButton->text = "Favorites";
favoriteButton->text = string::translate("Browser.favorites");
favoriteButton->box.size.x = 70;
headerLayout->addChild(favoriteButton);

clearButton = new ClearButton;
clearButton->box.size.x = 100;
clearButton->text = "Reset filters";
clearButton->text = string::translate("Browser.resetFilters");
clearButton->browser = this;
headerLayout->addChild(clearButton);

@@ -537,7 +540,7 @@ struct Browser : widget::OpaqueWidget {

UrlButton* libraryButton = new UrlButton;
libraryButton->box.size.x = 150;
libraryButton->text = "Browse VCV Library";
libraryButton->text = string::translate("Browser.browseLibrary");
libraryButton->url = "https://library.vcvrack.com/";
headerLayout->addChild(libraryButton);

@@ -776,7 +779,7 @@ struct Browser : widget::OpaqueWidget {
if (w->isVisible())
count++;
}
countLabel->text = string::f("%d %s", count, (count == 1) ? "module" : "modules");
countLabel->text = (count == 1) ? string::translate("Browser.modulesOne") : string::f(string::translate("Browser.modulesMany"), count);
}

void clear() {
@@ -892,7 +895,7 @@ inline void BrandButton::onAction(const ActionEvent& e) {
menu->box.size.x = box.size.x;

BrandItem* noneItem = new BrandItem;
noneItem->text = "All brands";
noneItem->text = string::translate("Browser.allBrands");
noneItem->brand = "";
noneItem->browser = browser;
menu->addChild(noneItem);
@@ -916,7 +919,7 @@ inline void BrandButton::onAction(const ActionEvent& e) {
}

inline void BrandButton::step() {
text = "Brand";
text = string::translate("Browser.brand");
if (!browser->brand.empty()) {
text += ": ";
text += browser->brand;
@@ -975,12 +978,12 @@ inline void TagButton::onAction(const ActionEvent& e) {
menu->box.size.x = box.size.x;

TagItem* noneItem = new TagItem;
noneItem->text = "All tags";
noneItem->text = string::translate("Browser.allTags");
noneItem->tagId = -1;
noneItem->browser = browser;
menu->addChild(noneItem);

menu->addChild(createMenuLabel(RACK_MOD_CTRL_NAME "+click to select multiple"));
menu->addChild(createMenuLabel(widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("Browser.tagsSelectMultiple")));
menu->addChild(new ui::MenuSeparator);

for (int tagId = 0; tagId < (int) tag::tagAliases.size(); tagId++) {
@@ -994,7 +997,7 @@ inline void TagButton::onAction(const ActionEvent& e) {
}

inline void TagButton::step() {
text = "Tags";
text = string::translate("Browser.tags");
if (!browser->tagIds.empty()) {
text += ": ";
bool firstTag = true;
@@ -1015,7 +1018,7 @@ inline void SortButton::onAction(const ActionEvent& e) {
menu->box.size.x = box.size.x;

for (int sortId = 0; sortId <= settings::BROWSER_SORT_RANDOM; sortId++) {
menu->addChild(createCheckMenuItem(sortNames[sortId], "",
menu->addChild(createCheckMenuItem(getSortNames()[sortId], "",
[=]() {return settings::browserSort == sortId;},
[=]() {
settings::browserSort = (settings::BrowserSort) sortId;


+ 1
- 1
src/app/MenuBar.cpp View File

@@ -1094,7 +1094,7 @@ struct InfoLabel : ui::Label {
double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0;
double meterAverage = APP->engine->getMeterAverage();
double meterMax = APP->engine->getMeterMax();
text += string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100);
text += string::f(string::translate("MenuBar.infoLabel"), fps, meterAverage * 100, meterMax * 100);
text += " ";
}



+ 5
- 5
src/app/ParamWidget.cpp View File

@@ -76,7 +76,7 @@ struct ParamValueItem : ui::MenuItem {
if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange* h = new history::ParamChange;
h->name = "set parameter";
h->name = string::translate("ParamWidget.history.setParam");
h->moduleId = paramWidget->module->id;
h->paramId = paramWidget->paramId;
h->oldValue = oldValue;
@@ -274,20 +274,20 @@ void ParamWidget::createContextMenu() {

// Initialize
if (pq && pq->resetEnabled && pq->isBounded()) {
menu->addChild(createMenuItem("Initialize", switchQuantity ? "" : "Double-click", [=]() {
menu->addChild(createMenuItem(string::translate("ParamWidget.initialize"), switchQuantity ? "" : string::translate("ParamWidget.doubleClick"), [=]() {
this->resetAction();
}));
}

// Fine
if (!switchQuantity) {
menu->addChild(createMenuItem("Fine adjust", RACK_MOD_CTRL_NAME "+drag", NULL, true));
menu->addChild(createMenuItem(string::translate("ParamWidget.fine"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("ParamWidget.fineDrag"), NULL, true));
}

// Unmap
engine::ParamHandle* paramHandle = module ? APP->engine->getParamHandle(module->id, paramId) : NULL;
if (paramHandle) {
menu->addChild(createMenuItem("Unmap", paramHandle->text, [=]() {
menu->addChild(createMenuItem(string::translate("ParamWidget.unmap"), paramHandle->text, [=]() {
APP->engine->updateParamHandle(paramHandle, -1, 0);
}));
}
@@ -306,7 +306,7 @@ void ParamWidget::resetAction() {
if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange* h = new history::ParamChange;
h->name = "reset parameter";
h->name = string::translate("ParamWidget.history.reset");
h->moduleId = module->id;
h->paramId = paramId;
h->oldValue = oldValue;


+ 12
- 12
src/app/PortWidget.cpp View File

@@ -61,14 +61,14 @@ struct PortTooltip : ui::Tooltip {
continue;
text += "\n";
if (portWidget->type == engine::Port::INPUT)
text += "From ";
text += string::translate("PortWidget.from");
else
text += "To ";
text += string::translate("PortWidget.to");
text += otherPw->module->model->getFullName();
text += ": ";
text += otherPw->getPortInfo()->getName();
text += " ";
text += (otherPw->type == engine::Port::INPUT) ? "input" : "output";
text += (otherPw->type == engine::Port::INPUT) ? string::translate("PortWidget.input") : string::translate("PortWidget.output");
}
}
Tooltip::step();
@@ -140,11 +140,11 @@ struct PortCableItem : ui::ColorDotMenuItem {
ui::Menu* createChildMenu() override {
ui::Menu* menu = new ui::Menu;

// menu->addChild(createMenuLabel(string::f("ID: %ld", cw->cable->id)));
// menu->addChild(createMenuLabel(string::f(string::translate("PortWidget.cableId"), cw->cable->id)));

for (NVGcolor color : settings::cableColors) {
// Include extra leading spaces for the color circle
CableColorItem* item = createMenuItem<CableColorItem>("Set color");
CableColorItem* item = createMenuItem<CableColorItem>(string::translate("PortWidget.setColor"));
item->disabled = color::isEqual(color, cw->color);
item->cw = cw;
item->color = color;
@@ -286,7 +286,7 @@ void PortWidget::createContextMenu() {
std::vector<CableWidget*> cws = APP->scene->rack->getCompleteCablesOnPort(this);
CableWidget* topCw = cws.empty() ? NULL : cws.back();

menu->addChild(createMenuItem("Delete top cable", RACK_MOD_SHIFT_NAME "+click",
menu->addChild(createMenuItem(string::translate("PortWidget.deleteTopCable"), widget::getKeyCommandName(0, RACK_MOD_SHIFT) + string::translate("PortWidget.click"),
[=]() {
if (!weakThis)
return;
@@ -296,7 +296,7 @@ void PortWidget::createContextMenu() {
));

{
PortCloneCableItem* item = createMenuItem<PortCloneCableItem>("Duplicate top cable", RACK_MOD_CTRL_NAME "+Shift+drag");
PortCloneCableItem* item = createMenuItem<PortCloneCableItem>(string::translate("PortWidget.cloneTopCable"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("PortWidget.drag"));
item->disabled = !topCw;
item->pw = this;
item->cw = topCw;
@@ -304,7 +304,7 @@ void PortWidget::createContextMenu() {
}

{
PortCreateCableItem* item = createMenuItem<PortCreateCableItem>("Create cable on top", RACK_MOD_CTRL_NAME "+drag");
PortCreateCableItem* item = createMenuItem<PortCreateCableItem>(string::translate("PortWidget.createCableTop"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("PortWidget.drag"));
item->pw = this;
menu->addChild(item);
}
@@ -317,7 +317,7 @@ void PortWidget::createContextMenu() {
std::string label = get(settings::cableLabels, colorId);
if (label == "")
label = string::f("#%lld", (long long) (colorId + 1));
PortCreateCableColorItem* item = createMenuItem<PortCreateCableColorItem>("Create cable: " + label);
PortCreateCableColorItem* item = createMenuItem<PortCreateCableColorItem>(string::translate("PortWidget.createCable") + label);
item->pw = this;
item->color = color;
item->colorId = colorId;
@@ -326,7 +326,7 @@ void PortWidget::createContextMenu() {

if (!cws.empty()) {
menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("Click+drag to grab cable"));
menu->addChild(createMenuLabel(string::translate("PortWidget.clickDrag") + string::translate("PortWidget.grabCable")));

// Cable items
for (auto it = cws.rbegin(); it != cws.rend(); it++) {
@@ -342,7 +342,7 @@ void PortWidget::createContextMenu() {
}

if (cws.size() > 1) {
PortAllCablesItem* item = createMenuItem<PortAllCablesItem>("All cables");
PortAllCablesItem* item = createMenuItem<PortAllCablesItem>(string::translate("PortWidget.allCables"));
item->pw = this;
item->cws = cws;
menu->addChild(item);
@@ -431,7 +431,7 @@ void PortWidget::onDragStart(const DragStartEvent& e) {
internal->history = NULL;
}
internal->history = new history::ComplexAction;
internal->history->name = "move cable";
internal->history->name = string::translate("PortWidget.history.moveCable");

std::vector<CableWidget*> cws;
int mods = APP->window->getMods();


+ 15
- 15
src/plugin/Model.cpp View File

@@ -106,16 +106,16 @@ std::string Model::getManualUrl() {

void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
// plugin
menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.plugin") + plugin->name, "", [=]() {
system::openBrowser(plugin->pluginUrl);
}, plugin->pluginUrl == ""));

// version
menu->addChild(createMenuLabel("Version: " + plugin->version));
menu->addChild(createMenuLabel(string::translate("Model.version") + plugin->version));

// author
if (plugin->author != "") {
menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.author") + plugin->author, "", [=]() {
system::openBrowser(plugin->authorUrl);
}, plugin->authorUrl.empty()));
}
@@ -123,17 +123,17 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
// license
std::string license = plugin->license;
if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) {
menu->addChild(createMenuItem("License: Open in browser", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.licenseBrowser"), "", [=]() {
system::openBrowser(license);
}));
}
else if (license != "") {
menu->addChild(createMenuLabel("License: " + license));
menu->addChild(createMenuLabel(string::translate("Model.license") + license));
}

// tags
if (!tagIds.empty()) {
menu->addChild(createMenuLabel("Tags:"));
menu->addChild(createMenuLabel(string::translate("Model.tags")));
for (int tagId : tagIds) {
menu->addChild(createMenuLabel("• " + tag::getTag(tagId)));
}
@@ -142,13 +142,13 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
menu->addChild(new ui::MenuSeparator);

// VCV Library page
menu->addChild(createMenuItem("VCV Library page", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.library"), "", [=]() {
system::openBrowser("https://library.vcvrack.com/" + plugin->slug + "/" + slug);
}));

// modularGridUrl
if (modularGridUrl != "") {
menu->addChild(createMenuItem("ModularGrid page", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.modularGrid"), "", [=]() {
system::openBrowser(modularGridUrl);
}));
}
@@ -156,42 +156,42 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
// manual
std::string manualUrl = getManualUrl();
if (manualUrl != "") {
menu->addChild(createMenuItem("User manual", widget::getKeyCommandName(GLFW_KEY_F1, RACK_MOD_CTRL), [=]() {
menu->addChild(createMenuItem(string::translate("Model.manual"), widget::getKeyCommandName(GLFW_KEY_F1, RACK_MOD_CTRL), [=]() {
system::openBrowser(manualUrl);
}));
}

// donate
if (plugin->donateUrl != "") {
menu->addChild(createMenuItem("Donate", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.donate"), "", [=]() {
system::openBrowser(plugin->donateUrl);
}));
}

// source code
if (plugin->sourceUrl != "") {
menu->addChild(createMenuItem("Source code", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.source"), "", [=]() {
system::openBrowser(plugin->sourceUrl);
}));
}

// changelog
if (plugin->changelogUrl != "") {
menu->addChild(createMenuItem("Changelog", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.changelog"), "", [=]() {
system::openBrowser(plugin->changelogUrl);
}));
}

// author email
if (plugin->authorEmail != "") {
menu->addChild(createMenuItem("Author email", "Copy to clipboard", [=]() {
menu->addChild(createMenuItem(string::translate("Model.authorEmail"), string::translate("Model.authorEmailCopy"), [=]() {
glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str());
}));
}

// plugin folder
if (plugin->path != "") {
menu->addChild(createMenuItem("Open plugin folder", "", [=]() {
menu->addChild(createMenuItem(string::translate("Model.pluginDir"), "", [=]() {
system::openDirectory(plugin->path);
}));
}
@@ -200,7 +200,7 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : "";
if (isFavorite())
favoriteRightText += " " CHECKMARK_STRING;
menu->addChild(createMenuItem("Favorite", favoriteRightText,
menu->addChild(createMenuItem(string::translate("Model.favorite"), favoriteRightText,
[=]() {
setFavorite(!isFavorite());
}


+ 30
- 19
src/widget/event.cpp View File

@@ -3,6 +3,7 @@
#include <context.hpp>
#include <window/Window.hpp>
#include <system.hpp>
#include <string.hpp>


namespace rack {
@@ -10,9 +11,12 @@ namespace widget {


std::string getKeyName(int key) {
if (key < 32)
return "";

// glfwGetKeyName overrides
switch (key) {
case GLFW_KEY_SPACE: return "Space";
case GLFW_KEY_SPACE: return string::translate("key.space");
}

// Printable characters
@@ -22,21 +26,21 @@ std::string getKeyName(int key) {

// Unprintable keys with names
switch (key) {
case GLFW_KEY_ESCAPE: return "Escape";
case GLFW_KEY_ENTER: return "Enter";
case GLFW_KEY_TAB: return "Tab";
case GLFW_KEY_BACKSPACE: return "Backspace";
case GLFW_KEY_INSERT: return "Insert";
case GLFW_KEY_DELETE: return "Delete";
case GLFW_KEY_RIGHT: return "Right";
case GLFW_KEY_LEFT: return "Left";
case GLFW_KEY_DOWN: return "Down";
case GLFW_KEY_UP: return "Up";
case GLFW_KEY_PAGE_UP: return "Page Up";
case GLFW_KEY_PAGE_DOWN: return "Page Down";
case GLFW_KEY_HOME: return "Home";
case GLFW_KEY_END: return "End";
case GLFW_KEY_KP_ENTER: return "Enter";
case GLFW_KEY_ESCAPE: return string::translate("key.escape");
case GLFW_KEY_ENTER: return string::translate("key.enter");
case GLFW_KEY_TAB: return string::translate("key.tab");
case GLFW_KEY_BACKSPACE: return string::translate("key.backspace");
case GLFW_KEY_INSERT: return string::translate("key.insert");
case GLFW_KEY_DELETE: return string::translate("key.delete");
case GLFW_KEY_RIGHT: return string::translate("key.right");
case GLFW_KEY_LEFT: return string::translate("key.left");
case GLFW_KEY_DOWN: return string::translate("key.down");
case GLFW_KEY_UP: return string::translate("key.up");
case GLFW_KEY_PAGE_UP: return string::translate("key.pageUp");
case GLFW_KEY_PAGE_DOWN: return string::translate("key.pageDown");
case GLFW_KEY_HOME: return string::translate("key.home");
case GLFW_KEY_END: return string::translate("key.end");
case GLFW_KEY_KP_ENTER: return string::translate("key.enter");
}

if (GLFW_KEY_F1 <= key && key <= GLFW_KEY_F25)
@@ -49,13 +53,20 @@ std::string getKeyName(int key) {
std::string getKeyCommandName(int key, int mods) {
std::string modsName;
if (mods & RACK_MOD_CTRL) {
modsName += RACK_MOD_CTRL_NAME "+";
#if defined ARCH_MAC
modsName += "⌘";
#else
modsName += string::translate("key.ctrl");
#endif
modsName += "+";
}
if (mods & GLFW_MOD_SHIFT) {
modsName += RACK_MOD_SHIFT_NAME "+";
modsName += string::translate("key.shift");
modsName += "+";
}
if (mods & GLFW_MOD_ALT) {
modsName += RACK_MOD_ALT_NAME "+";
modsName += string::translate("key.alt");
modsName += "+";
}
return modsName + getKeyName(key);
}


+ 81
- 1
translations/en.json View File

@@ -1,5 +1,25 @@
{
"language": "English",
"translators": "",
"key.space": "Space",
"key.escape": "Escape",
"key.enter": "Enter",
"key.tab": "Tab",
"key.backspace": "Backspace",
"key.insert": "Insert",
"key.delete": "Delete",
"key.right": "Right",
"key.left": "Left",
"key.down": "Down",
"key.up": "Up",
"key.pageUp": "Page Up",
"key.pageDown": "Page Down",
"key.home": "Home",
"key.end": "End",
"key.ctrl": "Ctrl",
"key.shift": "Shift",
"key.alt": "Alt",
"MenuBar.infoLabel": "%.1f fps %.1f%% avg %.1f%% max",
"MenuBar.file": "File",
"MenuBar.file.new": "New",
"MenuBar.file.open": "Open",
@@ -146,5 +166,65 @@
"RackWidget.duplicate": "Duplicate",
"RackWidget.duplicateWithCables": "with cables",
"RackWidget.delete": "Delete",
"RackWidget.history.clearCables": "clear cables"
"RackWidget.history.clearCables": "clear cables",
"Model.plugin": "Plugin: ",
"Model.version": "Version: ",
"Model.author": "Author: ",
"Model.licenseBrowser": "License: Open in browser",
"Model.license": "License: ",
"Model.tags": "Tags:",
"Model.library": "VCV Library page",
"Model.modularGrid": "ModularGrid page",
"Model.manual": "User manual",
"Model.donate": "Donate",
"Model.source": "Source code",
"Model.changelog": "Changelog",
"Model.authorEmail": "Author email",
"Model.authorEmailCopy": "Copy to clipboard",
"Model.pluginDir": "Open plugin folder",
"Model.favorite": "Favorite",
"Browser.history.addModule": "add module",
"Browser.tooltipTags": "Tags: ",
"Browser.sort.lastUpdated": "Last updated",
"Browser.sort.lastUsed": "Last used",
"Browser.sort.mostUsed": "Most used",
"Browser.sort.brand": "Brand",
"Browser.sort.moduleName": "Module name",
"Browser.sort.random": "Random",
"Browser.sort": "Sort: ",
"Browser.zoom": "Zoom: ",
"Browser.searchModules": "Search modules",
"Browser.favorites": "Favorites",
"Browser.resetFilters": "Reset filters",
"Browser.browseLibrary": "Browse VCV Library",
"Browser.modulesOne": "1 module",
"Browser.modulesMany": "%d modules",
"Browser.allBrands": "All brands",
"Browser.brand": "Brand",
"Browser.allTags": "All tags",
"Browser.tagsSelectMultiple": "click to select multiple",
"Browser.tags": "Tags",
"ParamWidget.history.setParam": "set parameter",
"ParamWidget.initialize": "Initialize",
"ParamWidget.doubleClick": "Double-click",
"ParamWidget.fine": "Fine adjust",
"ParamWidget.fineDrag": "drag",
"ParamWidget.unmap": "Unmap",
"ParamWidget.history.reset": "reset parameter",
"PortWidget.from": "From ",
"PortWidget.to": "To ",
"PortWidget.input": "input",
"PortWidget.output": "output",
"PortWidget.cableId": "ID: %ld",
"PortWidget.setColor": "Set color",
"PortWidget.deleteTopCable": "Delete top cable",
"PortWidget.click": "click",
"PortWidget.cloneTopCable": "Duplicate top cable",
"PortWidget.createCableTop": "Create cable on top",
"PortWidget.drag": "drag",
"PortWidget.createCable": "Create cable: ",
"PortWidget.clickDrag": "Click+drag",
"PortWidget.grabCable": " to grab cable",
"PortWidget.allCables": "All cables",
"PortWidget.history.moveCable": "move cable"
}

Loading…
Cancel
Save