Browse Source

Move English strings to translation file.

tags/v2.6.1
Andrew Belt 5 months ago
parent
commit
ad30d3a5c2
18 changed files with 202 additions and 116 deletions
  1. +6
    -6
      adapters/standalone.cpp
  2. +21
    -24
      src/app/AudioDisplay.cpp
  3. +1
    -1
      src/app/Browser.cpp
  4. +2
    -2
      src/app/Knob.cpp
  5. +13
    -13
      src/app/MidiDisplay.cpp
  6. +2
    -2
      src/app/ModuleLightWidget.cpp
  7. +2
    -2
      src/app/ParamWidget.cpp
  8. +4
    -4
      src/app/PortWidget.cpp
  9. +1
    -1
      src/app/Switch.cpp
  10. +37
    -22
      src/app/TipWindow.cpp
  11. +1
    -3
      src/engine/PortInfo.cpp
  12. +7
    -7
      src/library.cpp
  13. +2
    -2
      src/midi.cpp
  14. +11
    -15
      src/patch.cpp
  15. +3
    -1
      src/plugin/Model.cpp
  16. +4
    -4
      src/ui/TextField.cpp
  17. +1
    -0
      src/widget/event.cpp
  18. +84
    -7
      translations/en.json

+ 6
- 6
adapters/standalone.cpp View File

@@ -59,7 +59,7 @@ int main(int argc, char* argv[]) {
// Handle will be closed by Windows when the process ends // Handle will be closed by Windows when the process ends
HANDLE instanceMutex = CreateMutexW(NULL, true, string::UTF8toUTF16(APP_NAME).c_str()); HANDLE instanceMutex = CreateMutexW(NULL, true, string::UTF8toUTF16(APP_NAME).c_str());
if (GetLastError() == ERROR_ALREADY_EXISTS) { if (GetLastError() == ERROR_ALREADY_EXISTS) {
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "VCV Rack is already running. Multiple Rack instances are not supported.");
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, string::translate("standalone.multipleInstances"));
exit(1); exit(1);
} }
(void) instanceMutex; (void) instanceMutex;
@@ -174,7 +174,8 @@ int main(int argc, char* argv[]) {
} }
catch (Exception& e) { catch (Exception& e) {
std::string msg = e.what(); std::string msg = e.what();
msg += "\n\nReset settings to default?";
msg += "\n\n";
msg += string::translate("standalone.resetSettings");
if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, msg.c_str())) { if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, msg.c_str())) {
exit(1); exit(1);
} }
@@ -184,7 +185,7 @@ int main(int argc, char* argv[]) {
// Check existence of the system res/ directory // Check existence of the system res/ directory
std::string resDir = asset::system("res"); std::string resDir = asset::system("res");
if (!system::isDirectory(resDir)) { if (!system::isDirectory(resDir)) {
std::string message = string::f("VCV Rack's resource directory \"%s\" does not exist. Make sure Rack is correctly installed and launched.", resDir.c_str());
std::string message = string::f(string::translate("standalone.resDir"), resDir);
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, message.c_str()); osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, message.c_str());
exit(1); exit(1);
} }
@@ -196,8 +197,7 @@ int main(int argc, char* argv[]) {
rtaudioInit(); rtaudioInit();
#if defined ARCH_MAC #if defined ARCH_MAC
if (rtaudioIsMicrophoneBlocked()) { if (rtaudioIsMicrophoneBlocked()) {
std::string msg = "VCV Rack cannot access audio input because Microphone permission is blocked.";
msg += "\n\nGive permission to Rack by opening Apple's System Settings and enabling Privacy & Security > Microphone > " + APP_NAME + " " + APP_VERSION_MAJOR + " " + APP_EDITION_NAME + ".";
std::string msg = string::f(string::translate("standalone.micPermission"), APP_NAME + " " + APP_VERSION_MAJOR + " " + APP_EDITION_NAME);
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, msg.c_str()); osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, msg.c_str());
} }
#endif #endif
@@ -252,7 +252,7 @@ int main(int argc, char* argv[]) {
#endif #endif


// Initialize patch // Initialize patch
if (logger::wasTruncated() && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "VCV Rack crashed during the last session, possibly due to a buggy module in your patch. Clear your patch and start over?")) {
if (logger::wasTruncated() && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, string::translate("standalone.crashed").c_str())) {
// Do nothing, which leaves a blank patch // Do nothing, which leaves a blank patch
} }
else { else {


+ 21
- 24
src/app/AudioDisplay.cpp View File

@@ -49,14 +49,14 @@ static void appendAudioDriverMenu(ui::Menu* menu, audio::Port* port) {


void AudioDriverChoice::onAction(const ActionEvent& e) { void AudioDriverChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("Audio driver"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.audioDriver")));
appendAudioDriverMenu(menu, port); appendAudioDriverMenu(menu, port);
} }


void AudioDriverChoice::step() { void AudioDriverChoice::step() {
text = ""; text = "";
if (box.size.x >= 200.0) if (box.size.x >= 200.0)
text += "Driver: ";
text += string::translate("AudioDisplay.driver");
audio::Driver* driver = port ? port->getDriver() : NULL; audio::Driver* driver = port ? port->getDriver() : NULL;
std::string driverName = driver ? driver->getName() : ""; std::string driverName = driver ? driver->getName() : "";
if (driverName != "") { if (driverName != "") {
@@ -64,7 +64,7 @@ void AudioDriverChoice::step() {
color.a = 1.0; color.a = 1.0;
} }
else { else {
text += "(No driver)";
text += "(" + string::translate("AudioDisplay.noDriver") + ")";
color.a = 0.5; color.a = 0.5;
} }
} }
@@ -99,7 +99,7 @@ static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) {
AudioDeviceValueItem* item = new AudioDeviceValueItem; AudioDeviceValueItem* item = new AudioDeviceValueItem;
item->port = port; item->port = port;
item->deviceId = -1; item->deviceId = -1;
item->text = "(No device)";
item->text = "(" + string::translate("AudioDisplay.noDevice") + ")";
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); item->rightText = CHECKMARK(item->deviceId == port->getDeviceId());
menu->addChild(item); menu->addChild(item);
} }
@@ -132,14 +132,14 @@ static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) {


void AudioDeviceChoice::onAction(const ActionEvent& e) { void AudioDeviceChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("Audio device"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.audioDevice")));
appendAudioDeviceMenu(menu, port); appendAudioDeviceMenu(menu, port);
} }


void AudioDeviceChoice::step() { void AudioDeviceChoice::step() {
text = ""; text = "";
if (box.size.x >= 200.0) if (box.size.x >= 200.0)
text += "Device: ";
text += string::translate("AudioDisplay.device");
std::string detail = ""; std::string detail = "";
if (port && port->getDevice()) if (port && port->getDevice())
detail = getDetailTemplate(port->getDevice()->getName(), port->getNumInputs(), port->inputOffset, port->getNumOutputs(), port->outputOffset); detail = getDetailTemplate(port->getDevice()->getName(), port->getNumInputs(), port->inputOffset, port->getNumOutputs(), port->outputOffset);
@@ -149,10 +149,7 @@ void AudioDeviceChoice::step() {
color.a = 1.0; color.a = 1.0;
} }
else { else {
if (box.size.x >= 80.0)
text += "(No device)";
else
text += "No device";
text += string::translate("AudioDisplay.noDevice");
color.a = 0.5; color.a = 0.5;
} }
} }
@@ -184,7 +181,7 @@ static void appendAudioSampleRateMenu(ui::Menu* menu, audio::Port* port) {
sampleRates.insert(port->getSampleRate()); sampleRates.insert(port->getSampleRate());


if (sampleRates.empty()) { if (sampleRates.empty()) {
menu->addChild(createMenuLabel("(Locked by device)"));
menu->addChild(createMenuLabel("(" + string::translate("AudioDisplay.lockedByDevice") + ")"));
} }
for (float sampleRate : sampleRates) { for (float sampleRate : sampleRates) {
if (sampleRate <= 0) if (sampleRate <= 0)
@@ -200,14 +197,14 @@ static void appendAudioSampleRateMenu(ui::Menu* menu, audio::Port* port) {


void AudioSampleRateChoice::onAction(const ActionEvent& e) { void AudioSampleRateChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("Sample rate"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.sampleRate")));
appendAudioSampleRateMenu(menu, port); appendAudioSampleRateMenu(menu, port);
} }


void AudioSampleRateChoice::step() { void AudioSampleRateChoice::step() {
text = ""; text = "";
if (box.size.x >= 100.0) if (box.size.x >= 100.0)
text += "Rate: ";
text += string::translate("AudioDisplay.sampleRateColon");
float sampleRate = port ? port->getSampleRate() : 0; float sampleRate = port ? port->getSampleRate() : 0;
if (sampleRate > 0) { if (sampleRate > 0) {
text += string::f("%g", sampleRate / 1000.f); text += string::f("%g", sampleRate / 1000.f);
@@ -247,7 +244,7 @@ static void appendAudioBlockSizeMenu(ui::Menu* menu, audio::Port* port) {
blockSizes.insert(port->getBlockSize()); blockSizes.insert(port->getBlockSize());


if (blockSizes.empty()) { if (blockSizes.empty()) {
menu->addChild(createMenuLabel("(Locked by device)"));
menu->addChild(createMenuLabel("(" + string::translate("AudioDisplay.lockedByDevice") + ")"));
} }
for (int blockSize : blockSizes) { for (int blockSize : blockSizes) {
if (blockSize <= 0) if (blockSize <= 0)
@@ -264,14 +261,14 @@ static void appendAudioBlockSizeMenu(ui::Menu* menu, audio::Port* port) {


void AudioBlockSizeChoice::onAction(const ActionEvent& e) { void AudioBlockSizeChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("Block size"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.blockSize")));
appendAudioBlockSizeMenu(menu, port); appendAudioBlockSizeMenu(menu, port);
} }


void AudioBlockSizeChoice::step() { void AudioBlockSizeChoice::step() {
text = ""; text = "";
if (box.size.x >= 100.0) if (box.size.x >= 100.0)
text += "Block size: ";
text += string::translate("AudioDisplay.blockSizeColon");
int blockSize = port ? port->getBlockSize() : 0; int blockSize = port ? port->getBlockSize() : 0;
if (blockSize > 0) { if (blockSize > 0) {
text += string::f("%d", blockSize); text += string::f("%d", blockSize);
@@ -358,36 +355,36 @@ void AudioButton::onAction(const ActionEvent& e) {




void appendAudioMenu(ui::Menu* menu, audio::Port* port) { void appendAudioMenu(ui::Menu* menu, audio::Port* port) {
menu->addChild(createMenuLabel("Audio driver"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.audioDriver")));
appendAudioDriverMenu(menu, port); appendAudioDriverMenu(menu, port);


menu->addChild(new ui::MenuSeparator); menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("Audio device"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.audioDevice")));
appendAudioDeviceMenu(menu, port); appendAudioDeviceMenu(menu, port);


menu->addChild(new ui::MenuSeparator); menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("Sample rate"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.sampleRate")));
appendAudioSampleRateMenu(menu, port); appendAudioSampleRateMenu(menu, port);


menu->addChild(new ui::MenuSeparator); menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("Block size"));
menu->addChild(createMenuLabel(string::translate("AudioDisplay.blockSize")));
appendAudioBlockSizeMenu(menu, port); appendAudioBlockSizeMenu(menu, port);


// Uncomment this to use sub-menus instead of one big menu. // Uncomment this to use sub-menus instead of one big menu.


// AudioDriverItem* driverItem = createMenuItem<AudioDriverItem>("Audio driver", RIGHT_ARROW);
// AudioDriverItem* driverItem = createMenuItem<AudioDriverItem>(string::translate("AudioDisplay.audioDriver"), RIGHT_ARROW);
// driverItem->port = port; // driverItem->port = port;
// menu->addChild(driverItem); // menu->addChild(driverItem);


// AudioDeviceItem* deviceItem = createMenuItem<AudioDeviceItem>("Audio device", RIGHT_ARROW);
// AudioDeviceItem* deviceItem = createMenuItem<AudioDeviceItem>(string::translate("AudioDisplay.audioDevice"), RIGHT_ARROW);
// deviceItem->port = port; // deviceItem->port = port;
// menu->addChild(deviceItem); // menu->addChild(deviceItem);


// AudioSampleRateItem* sampleRateItem = createMenuItem<AudioSampleRateItem>("Sample rate", RIGHT_ARROW);
// AudioSampleRateItem* sampleRateItem = createMenuItem<AudioSampleRateItem>(string::translate("AudioDisplay.sampleRate"), RIGHT_ARROW);
// sampleRateItem->port = port; // sampleRateItem->port = port;
// menu->addChild(sampleRateItem); // menu->addChild(sampleRateItem);


// AudioBlockSizeItem* blockSizeItem = createMenuItem<AudioBlockSizeItem>("Block size", RIGHT_ARROW);
// AudioBlockSizeItem* blockSizeItem = createMenuItem<AudioBlockSizeItem>(string::translate("AudioDisplay.blockSize"), RIGHT_ARROW);
// blockSizeItem->port = port; // blockSizeItem->port = port;
// menu->addChild(blockSizeItem); // menu->addChild(blockSizeItem);
} }


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

@@ -989,7 +989,7 @@ inline void TagButton::onAction(const ActionEvent& e) {
noneItem->browser = browser; noneItem->browser = browser;
menu->addChild(noneItem); menu->addChild(noneItem);


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


for (int tagId = 0; tagId < (int) tag::tagAliases.size(); tagId++) { for (int tagId = 0; tagId < (int) tag::tagAliases.size(); tagId++) {


+ 2
- 2
src/app/Knob.cpp View File

@@ -107,7 +107,7 @@ void Knob::onDragEnd(const DragEndEvent& e) {
if (!std::isnan(internal->oldValue) && internal->oldValue != newValue) { if (!std::isnan(internal->oldValue) && internal->oldValue != newValue) {
// Push ParamChange history action // Push ParamChange history action
history::ParamChange* h = new history::ParamChange; history::ParamChange* h = new history::ParamChange;
h->name = "move knob";
h->name = string::translate("Knob.history.move");
h->moduleId = module->id; h->moduleId = module->id;
h->paramId = paramId; h->paramId = paramId;
h->oldValue = internal->oldValue; h->oldValue = internal->oldValue;
@@ -302,7 +302,7 @@ void Knob::onLeave(const LeaveEvent& e) {
if (!std::isnan(internal->oldValue) && internal->oldValue != newValue) { if (!std::isnan(internal->oldValue) && internal->oldValue != newValue) {
// Push ParamChange history action // Push ParamChange history action
history::ParamChange* h = new history::ParamChange; history::ParamChange* h = new history::ParamChange;
h->name = "move knob";
h->name = string::translate("Knob.history.move");
h->moduleId = module->id; h->moduleId = module->id;
h->paramId = paramId; h->paramId = paramId;
h->oldValue = internal->oldValue; h->oldValue = internal->oldValue;


+ 13
- 13
src/app/MidiDisplay.cpp View File

@@ -31,14 +31,14 @@ static void appendMidiDriverMenu(ui::Menu* menu, midi::Port* port) {


void MidiDriverChoice::onAction(const ActionEvent& e) { void MidiDriverChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("MIDI driver"));
menu->addChild(createMenuLabel(string::translate("MidiDisplay.driver")));
appendMidiDriverMenu(menu, port); appendMidiDriverMenu(menu, port);
} }


void MidiDriverChoice::step() { void MidiDriverChoice::step() {
text = (port && port->driver) ? port->getDriver()->getName() : ""; text = (port && port->driver) ? port->getDriver()->getName() : "";
if (text.empty()) { if (text.empty()) {
text = "(No driver)";
text = "(" + string::translate("MidiDisplay.noDriver") + ")";
color.a = 0.5f; color.a = 0.5f;
} }
else { else {
@@ -72,7 +72,7 @@ static void appendMidiDeviceMenu(ui::Menu* menu, midi::Port* port) {
MidiDeviceValueItem* item = new MidiDeviceValueItem; MidiDeviceValueItem* item = new MidiDeviceValueItem;
item->port = port; item->port = port;
item->deviceId = -1; item->deviceId = -1;
item->text = "(No device)";
item->text = "(" + string::translate("MidiDisplay.noDevice") + ")";
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); item->rightText = CHECKMARK(item->deviceId == port->getDeviceId());
menu->addChild(item); menu->addChild(item);
} }
@@ -89,14 +89,14 @@ static void appendMidiDeviceMenu(ui::Menu* menu, midi::Port* port) {


void MidiDeviceChoice::onAction(const ActionEvent& e) { void MidiDeviceChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("MIDI device"));
menu->addChild(createMenuLabel(string::translate("MidiDisplay.device")));
appendMidiDeviceMenu(menu, port); appendMidiDeviceMenu(menu, port);
} }


void MidiDeviceChoice::step() { void MidiDeviceChoice::step() {
text = (port && port->device) ? port->getDevice()->getName() : ""; text = (port && port->device) ? port->getDevice()->getName() : "";
if (text.empty()) { if (text.empty()) {
text = "(No device)";
text = "(" + string::translate("MidiDisplay.noDevice") + ")";
color.a = 0.5f; color.a = 0.5f;
} }
else { else {
@@ -138,12 +138,12 @@ static void appendMidiChannelMenu(ui::Menu* menu, midi::Port* port) {


void MidiChannelChoice::onAction(const ActionEvent& e) { void MidiChannelChoice::onAction(const ActionEvent& e) {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
menu->addChild(createMenuLabel("MIDI channel"));
menu->addChild(createMenuLabel(string::translate("MidiDisplay.channel")));
appendMidiChannelMenu(menu, port); appendMidiChannelMenu(menu, port);
} }


void MidiChannelChoice::step() { void MidiChannelChoice::step() {
text = port ? port->getChannelName(port->getChannel()) : "Channel 1";
text = port ? port->getChannelName(port->getChannel()) : string::translate("MidiDisplay.channel1");
} }


struct MidiChannelItem : ui::MenuItem { struct MidiChannelItem : ui::MenuItem {
@@ -203,28 +203,28 @@ void MidiButton::onAction(const ActionEvent& e) {




void appendMidiMenu(ui::Menu* menu, midi::Port* port) { void appendMidiMenu(ui::Menu* menu, midi::Port* port) {
menu->addChild(createMenuLabel("MIDI driver"));
menu->addChild(createMenuLabel(string::translate("MidiDisplay.driver")));
appendMidiDriverMenu(menu, port); appendMidiDriverMenu(menu, port);


menu->addChild(new ui::MenuSeparator); menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("MIDI device"));
menu->addChild(createMenuLabel(string::translate("MidiDisplay.device")));
appendMidiDeviceMenu(menu, port); appendMidiDeviceMenu(menu, port);


menu->addChild(new ui::MenuSeparator); menu->addChild(new ui::MenuSeparator);
// menu->addChild(createMenuLabel("MIDI channel"));
// menu->addChild(createMenuLabel(string::translate("MidiDisplay.channel")));
// appendMidiChannelMenu(menu, port); // appendMidiChannelMenu(menu, port);


// Uncomment this to use sub-menus instead of one big menu. // Uncomment this to use sub-menus instead of one big menu.


// MidiDriverItem* driverItem = createMenuItem<MidiDriverItem>("MIDI driver", RIGHT_ARROW);
// MidiDriverItem* driverItem = createMenuItem<MidiDriverItem>(string::translate("MidiDisplay.driver"), RIGHT_ARROW);
// driverItem->port = port; // driverItem->port = port;
// menu->addChild(driverItem); // menu->addChild(driverItem);


// MidiDeviceItem* deviceItem = createMenuItem<MidiDeviceItem>("MIDI device", RIGHT_ARROW);
// MidiDeviceItem* deviceItem = createMenuItem<MidiDeviceItem>(string::translate("MidiDisplay.device"), RIGHT_ARROW);
// deviceItem->port = port; // deviceItem->port = port;
// menu->addChild(deviceItem); // menu->addChild(deviceItem);


MidiChannelItem* channelItem = createMenuItem<MidiChannelItem>("MIDI channel", RIGHT_ARROW);
MidiChannelItem* channelItem = createMenuItem<MidiChannelItem>(string::translate("MidiDisplay.channel"), RIGHT_ARROW);
channelItem->port = port; channelItem->port = port;
menu->addChild(channelItem); menu->addChild(channelItem);
} }


+ 2
- 2
src/app/ModuleLightWidget.cpp View File

@@ -22,8 +22,8 @@ struct LightTooltip : ui::Tooltip {
if (!lightInfo) if (!lightInfo)
return; return;
// Label // Label
text = lightInfo->getName();
text += " light";
std::string name = lightInfo->getName();
text = string::f(string::translate("ModuleLightWidget.light"), name);
// Description // Description
std::string description = lightInfo->getDescription(); std::string description = lightInfo->getDescription();
if (description != "") { if (description != "") {


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

@@ -274,14 +274,14 @@ void ParamWidget::createContextMenu() {


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


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


// Unmap // Unmap


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

@@ -286,7 +286,7 @@ void PortWidget::createContextMenu() {
std::vector<CableWidget*> cws = APP->scene->rack->getCompleteCablesOnPort(this); std::vector<CableWidget*> cws = APP->scene->rack->getCompleteCablesOnPort(this);
CableWidget* topCw = cws.empty() ? NULL : cws.back(); CableWidget* topCw = cws.empty() ? NULL : cws.back();


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


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


{ {
PortCreateCableItem* item = createMenuItem<PortCreateCableItem>(string::translate("PortWidget.createCableTop"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("PortWidget.drag"));
PortCreateCableItem* item = createMenuItem<PortCreateCableItem>(string::translate("PortWidget.createCableTop"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("key.drag"));
item->pw = this; item->pw = this;
menu->addChild(item); menu->addChild(item);
} }
@@ -326,7 +326,7 @@ void PortWidget::createContextMenu() {


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


// Cable items // Cable items
for (auto it = cws.rbegin(); it != cws.rend(); it++) { for (auto it = cws.rbegin(); it != cws.rend(); it++) {


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

@@ -103,7 +103,7 @@ void Switch::onDragStart(const DragStartEvent& e) {
if (oldValue != newValue) { if (oldValue != newValue) {
// Push ParamChange history action // Push ParamChange history action
history::ParamChange* h = new history::ParamChange; history::ParamChange* h = new history::ParamChange;
h->name = "move switch";
h->name = string::translate("Switch.history.move");
h->moduleId = module->id; h->moduleId = module->id;
h->paramId = paramId; h->paramId = paramId;
h->oldValue = oldValue; h->oldValue = oldValue;


+ 37
- 22
src/app/TipWindow.cpp View File

@@ -31,23 +31,36 @@ struct TipInfo {
}; };




// Remember to use “smart quotes.”
static const std::vector<TipInfo> tipInfos = {
{"To add a module to your patch, right-click an empty rack space or press Enter. Then click and drag a module from the Module Browser into the desired rack space.\n\nTo select multiple modules, click and drag on empty rack space.", "", ""},
{"To move around your patch, use the scroll bars, drag while holding the middle mouse button, " RACK_MOD_ALT_NAME "+click and drag, or hold the arrow keys. Arrow key movement speed can be adjusted by holding " RACK_MOD_CTRL_NAME ", " RACK_MOD_SHIFT_NAME ", or " RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME ".\n\nTo zoom in and out, drag the Zoom slider in the View menu, hold " RACK_MOD_CTRL_NAME " and scroll, or press " RACK_MOD_CTRL_NAME "+= and " RACK_MOD_CTRL_NAME "+minus.", "", ""},
{"You can use Rack in fullscreen mode by selecting “View > Fullscreen“ or pressing F11.\n\nIn fullscreen mode, the menu bar and scroll bars are hidden. This is ideal for screen recording with VCV Recorder.", "Get VCV Recorder", "https://vcvrack.com/Recorder"},
{"You can browse thousands of modules on the VCV Library website.\n\nRegister for a VCV account, log into Rack using the Library menu, and browse the VCV Library to add or purchase modules. Keep all plugins up to date by clicking “Library > Update all”.", "VCV Library", "https://library.vcvrack.com/"},
{"Some developers of free plugins accept donations. Right-click your favorite module's panel and select “Info > Donate”.\n\nYou can also donate via the module's VCV Library page.", "VCV Library", "https://library.vcvrack.com/"},
{"Want to use VCV Rack in your DAW? VCV Rack Pro is available for VST2, VST3, Audio Unit, and CLAP hosts.\n\nSupported DAWs include Ableton Live, Cubase, FL Studio, Reason, Bitwig, Reaper, Mixbus, Studio One, Cakewalk, Logic Pro, and GarageBand.", "Learn more", "https://vcvrack.com/Rack"},
{"You can learn more about VCV Rack by browsing the official manual.", "VCV Rack manual", "https://vcvrack.com/manual/"},
{"Follow VCV Rack on Twitter for new module announcements, development news, and featured artists/music.", "Twitter @vcvrack", "https://twitter.com/vcvrack"},
{"Patch cables in Rack can carry up to 16 signals. You can use this ability to build polyphonic patches using modules having the “Polyphonic” tag. Cables carrying more than 1 signal appear thicker than normal cables. To try out polyphony, add the VCV MIDI-to-CV module to your patch, right-click its panel, and select your desired number of polyphonic channels.", "Learn more about polyphony in VCV Rack", "https://vcvrack.com/manual/Polyphony"},
{"Know C++ programming and want to create your own modules for Rack? Developing Rack modules is a great way to learn digital signal processing and quickly test your ideas with an easy-to-learn platform.\n\nDownload the Rack SDK and follow the development tutorial to get started.", "Plugin Development Tutorial", "https://vcvrack.com/manual/PluginDevelopmentTutorial"},
{"Wondering how to use a particular module? Right-click its panel and choose “Info > User manual”.\n\nYou can also open the module's Info menu to view the module's tags, website, VCV Library page, and changelog, if available.", "", ""},
{"Did you know that the VCV Library is integrated with ModularGrid? If a module is available as a hardware Eurorack module, right-click its panel and choose “Info > ModularGrid”, or click the “ModularGrid” link on its VCV Library page.\n\nOn ModularGrid.net, search for the VCV logo on certain module's entry pages.", "Example: Grayscale Permutation on ModularGrid", "https://www.modulargrid.net/e/grayscale-permutation-18hp"},
{"When any context menu is open, you can " RACK_MOD_CTRL_NAME "+click a menu item to keep the menu open. This can be useful when browsing module presets or settings.", "", ""},
// {"", "", ""},
};
static std::vector<TipInfo> getTipInfos() {
// Remember to use “smart quotes.”
return {
{string::translate("TipWindow.addModule"), "", ""},
{string::f(string::translate("TipWindow.moveRack"),
widget::getKeyCommandName(0, RACK_MOD_ALT) + string::translate("key.click"),
string::translate("key.ctrl"),
string::translate("key.shift"),
string::translate("key.ctrl"),
string::translate("key.shift"),
string::translate("key.ctrl"),
widget::getKeyCommandName(GLFW_KEY_EQUAL, RACK_MOD_CTRL),
widget::getKeyCommandName(GLFW_KEY_MINUS, RACK_MOD_CTRL)),
"", ""},
{string::translate("TipWindow.fullscreen"), string::translate("TipWindow.fullscreenButton"), "https://vcvrack.com/Recorder"},
{string::translate("TipWindow.library"), string::translate("TipWindow.libraryButton"), "https://library.vcvrack.com/"},
{string::translate("TipWindow.donation"), string::translate("TipWindow.libraryButton"), "https://library.vcvrack.com/"},
{string::translate("TipWindow.daw"), string::translate("TipWindow.learnMore"), "https://vcvrack.com/Rack"},
{string::translate("TipWindow.manual"), string::translate("TipWindow.manualButton"), "https://vcvrack.com/manual/"},
{string::translate("TipWindow.twitter"), string::translate("TipWindow.twitterHandle"), "https://twitter.com/vcvrack"},
{string::translate("TipWindow.polyphony"), string::translate("TipWindow.polyphonyButton"), "https://vcvrack.com/manual/Polyphony"},
{string::translate("TipWindow.develop"), string::translate("TipWindow.developButton"), "https://vcvrack.com/manual/PluginDevelopmentTutorial"},
{string::translate("TipWindow.moduleManual"), "", ""},
{string::translate("TipWindow.modularGrid"), string::translate("TipWindow.modularGridButton"), "https://www.modulargrid.net/e/grayscale-permutation-18hp"},
{string::f(string::translate("TipWindow.menuKeepOpen"),
widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("key.click")),
"", ""},
// {"", "", ""},
};
}




struct TipWindow : widget::OpaqueWidget { struct TipWindow : widget::OpaqueWidget {
@@ -74,7 +87,7 @@ struct TipWindow : widget::OpaqueWidget {
// header->box.size.x = box.size.x - 2*margin; // header->box.size.x = box.size.x - 2*margin;
header->box.size.y = 20; header->box.size.y = 20;
header->fontSize = 20; header->fontSize = 20;
header->text = "Welcome to " + APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION;
header->text = string::f(string::translate("TipWindow.welcome"), APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION);
layout->addChild(header); layout->addChild(header);


label = new ui::Label; label = new ui::Label;
@@ -108,7 +121,7 @@ struct TipWindow : widget::OpaqueWidget {


ui::OptionButton* showButton = new ui::OptionButton; ui::OptionButton* showButton = new ui::OptionButton;
showButton->box.size.x = 200; showButton->box.size.x = 200;
showButton->text = "Show tips at startup";
showButton->text = string::translate("TipWindow.startup");
showButton->quantity = &showQuantity; showButton->quantity = &showQuantity;
buttonLayout->addChild(showButton); buttonLayout->addChild(showButton);


@@ -120,7 +133,7 @@ struct TipWindow : widget::OpaqueWidget {
}; };
PreviousButton* prevButton = new PreviousButton; PreviousButton* prevButton = new PreviousButton;
prevButton->box.size.x = buttonWidth; prevButton->box.size.x = buttonWidth;
prevButton->text = "â—€ Previous";
prevButton->text = "â—€ " + string::translate("TipWindow.previous");
prevButton->tipWindow = this; prevButton->tipWindow = this;
buttonLayout->addChild(prevButton); buttonLayout->addChild(prevButton);


@@ -132,7 +145,7 @@ struct TipWindow : widget::OpaqueWidget {
}; };
NextButton* nextButton = new NextButton; NextButton* nextButton = new NextButton;
nextButton->box.size.x = buttonWidth; nextButton->box.size.x = buttonWidth;
nextButton->text = "â–¶ Next";
nextButton->text = "â–¶ " + string::translate("TipWindow.next");
nextButton->tipWindow = this; nextButton->tipWindow = this;
buttonLayout->addChild(nextButton); buttonLayout->addChild(nextButton);


@@ -144,7 +157,7 @@ struct TipWindow : widget::OpaqueWidget {
}; };
CloseButton* closeButton = new CloseButton; CloseButton* closeButton = new CloseButton;
closeButton->box.size.x = buttonWidth; closeButton->box.size.x = buttonWidth;
closeButton->text = "âś– Close";
closeButton->text = "âś– " + string::translate("TipWindow.close");
closeButton->tipWindow = this; closeButton->tipWindow = this;
buttonLayout->addChild(closeButton); buttonLayout->addChild(closeButton);


@@ -155,6 +168,8 @@ struct TipWindow : widget::OpaqueWidget {
} }


void advanceTip(int delta = 1) { void advanceTip(int delta = 1) {
std::vector<TipInfo> tipInfos = getTipInfos();

// Increment tip index // Increment tip index
settings::tipIndex = math::eucMod(settings::tipIndex + delta, (int) tipInfos.size()); settings::tipIndex = math::eucMod(settings::tipIndex + delta, (int) tipInfos.size());




+ 1
- 3
src/engine/PortInfo.cpp View File

@@ -15,9 +15,7 @@ std::string PortInfo::getName() {


std::string PortInfo::getFullName() { std::string PortInfo::getFullName() {
std::string name = getName(); std::string name = getName();
name += " ";
name += (type == Port::INPUT) ? "input" : "output";
return name;
return string::f((type == Port::INPUT) ? string::translate("PortInfo.input") : string::translate("PortInfo.output"), name);
} }






+ 7
- 7
src/library.cpp View File

@@ -114,7 +114,7 @@ void logIn(std::string email, std::string password) {
return; return;
DEFER({updateMutex.unlock();}); DEFER({updateMutex.unlock();});


loginStatus = "Logging in...";
loginStatus = string::translate("library.loggingIn");
json_t* reqJ = json_object(); json_t* reqJ = json_object();
json_object_set_new(reqJ, "email", json_string(email.c_str())); json_object_set_new(reqJ, "email", json_string(email.c_str()));
json_object_set_new(reqJ, "password", json_string(password.c_str())); json_object_set_new(reqJ, "password", json_string(password.c_str()));
@@ -123,7 +123,7 @@ void logIn(std::string email, std::string password) {
json_decref(reqJ); json_decref(reqJ);


if (!resJ) { if (!resJ) {
loginStatus = "No response from server";
loginStatus = string::translate("library.noResponse");
return; return;
} }
DEFER({json_decref(resJ);}); DEFER({json_decref(resJ);});
@@ -137,7 +137,7 @@ void logIn(std::string email, std::string password) {


json_t* tokenJ = json_object_get(resJ, "token"); json_t* tokenJ = json_object_get(resJ, "token");
if (!tokenJ) { if (!tokenJ) {
loginStatus = "No token in response";
loginStatus = string::translate("library.noToken");
return; return;
} }


@@ -172,14 +172,14 @@ void checkUpdates() {
if (isSyncing) if (isSyncing)
return; return;


updateStatus = "Querying for updates...";
updateStatus = string::translate("library.queryingUpdates");


// Check user token // Check user token
std::string userUrl = API_URL + "/user"; std::string userUrl = API_URL + "/user";
json_t* userResJ = network::requestJson(network::METHOD_GET, userUrl, NULL, getTokenCookies()); json_t* userResJ = network::requestJson(network::METHOD_GET, userUrl, NULL, getTokenCookies());
if (!userResJ) { if (!userResJ) {
WARN("Request for user account failed"); WARN("Request for user account failed");
updateStatus = "Could not query user account";
updateStatus = string::translate("library.queryAccountFailed");
return; return;
} }
DEFER({json_decref(userResJ);}); DEFER({json_decref(userResJ);});
@@ -202,7 +202,7 @@ void checkUpdates() {
json_decref(manifestsReq); json_decref(manifestsReq);
if (!manifestsResJ) { if (!manifestsResJ) {
WARN("Request for library manifests failed"); WARN("Request for library manifests failed");
updateStatus = "Could not query plugin manifests";
updateStatus = string::translate("library.queryManifestsFailed");
return; return;
} }
DEFER({json_decref(manifestsResJ);}); DEFER({json_decref(manifestsResJ);});
@@ -212,7 +212,7 @@ void checkUpdates() {
json_t* modulesResJ = network::requestJson(network::METHOD_GET, modulesUrl, NULL, getTokenCookies()); json_t* modulesResJ = network::requestJson(network::METHOD_GET, modulesUrl, NULL, getTokenCookies());
if (!modulesResJ) { if (!modulesResJ) {
WARN("Request for user's modules failed"); WARN("Request for user's modules failed");
updateStatus = "Could not query user's modules";
updateStatus = string::translate("library.queryModulesFailed");
return; return;
} }
DEFER({json_decref(modulesResJ);}); DEFER({json_decref(modulesResJ);});


+ 2
- 2
src/midi.cpp View File

@@ -150,9 +150,9 @@ void Port::setChannel(int channel) {


std::string Port::getChannelName(int channel) { std::string Port::getChannelName(int channel) {
if (channel < 0) if (channel < 0)
return "All channels";
return string::translate("midi.allChannels");
else else
return string::f("Channel %d", channel + 1);
return string::f(string::translate("midi.channelNum"), channel + 1);
} }


json_t* Port::toJson() { json_t* Port::toJson() {


+ 11
- 15
src/patch.cpp View File

@@ -145,7 +145,7 @@ void Manager::saveDialog() {
save(path); save(path);
} }
catch (Exception& e) { catch (Exception& e) {
std::string message = string::f("Could not save patch: %s", e.what());
std::string message = string::f(string::translate("patch.saveFailed"), e.what());
osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str()); osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());
return; return;
} }
@@ -195,7 +195,7 @@ void Manager::saveAsDialog(bool setPath) {
save(path); save(path);
} }
catch (Exception& e) { catch (Exception& e) {
std::string message = string::f("Could not save patch: %s", e.what());
std::string message = string::f(string::translate("patch.saveFailed"), e.what());
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
return; return;
} }
@@ -206,14 +206,14 @@ void Manager::saveAsDialog(bool setPath) {


void Manager::saveTemplateDialog() { void Manager::saveTemplateDialog() {
// Even if <user>/template.vcv doesn't exist, this message is still valid because it overrides the <system>/template.vcv patch. // Even if <user>/template.vcv doesn't exist, this message is still valid because it overrides the <system>/template.vcv patch.
if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Overwrite template patch?"))
if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, string::translate("patch.overwriteTemplate").c_str()))
return; return;


try { try {
save(templatePath); save(templatePath);
} }
catch (Exception& e) { catch (Exception& e) {
std::string message = string::f("Could not save template patch: %s", e.what());
std::string message = string::f(string::translate("patch.saveTemplateFailed"), e.what());
osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str()); osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());
return; return;
} }
@@ -316,7 +316,7 @@ void Manager::loadTemplate() {
load(factoryTemplatePath); load(factoryTemplatePath);
} }
catch (Exception& e) { catch (Exception& e) {
std::string message = string::f("Could not load system template patch, clearing rack: %s", e.what());
std::string message = string::f(string::translate("patch.loadTemplateFailed"), e.what());
osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str()); osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());


clear(); clear();
@@ -331,7 +331,7 @@ void Manager::loadTemplate() {




void Manager::loadTemplateDialog() { void Manager::loadTemplateDialog() {
if (!promptClear("The current patch is unsaved. Clear it and start a new patch?")) {
if (!promptClear(string::translate("patch.loadTemplateConfirm"))) {
return; return;
} }
loadTemplate(); loadTemplate();
@@ -373,7 +373,7 @@ void Manager::loadAction(std::string path) {
load(path); load(path);
} }
catch (Exception& e) { catch (Exception& e) {
std::string message = string::f("Could not load patch: %s", e.what());
std::string message = string::f(string::translate("patch.loadFailed"), e.what());
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
return; return;
} }
@@ -385,7 +385,7 @@ void Manager::loadAction(std::string path) {




void Manager::loadDialog() { void Manager::loadDialog() {
if (!promptClear("The current patch is unsaved. Clear it and open a new patch?"))
if (!promptClear(string::translate("patch.loadConfirm")))
return; return;


std::string dir; std::string dir;
@@ -415,7 +415,7 @@ void Manager::loadDialog() {




void Manager::loadPathDialog(std::string path) { void Manager::loadPathDialog(std::string path) {
if (!promptClear("The current patch is unsaved. Clear it and open the new patch?"))
if (!promptClear(string::translate("patch.loadConfirm")))
return; return;


loadAction(path); loadAction(path);
@@ -425,7 +425,7 @@ void Manager::loadPathDialog(std::string path) {
void Manager::revertDialog() { void Manager::revertDialog() {
if (path == "") if (path == "")
return; return;
if (!promptClear("Revert patch to the last saved state?"))
if (!promptClear(string::translate("patch.revertConfirm")))
return; return;


loadAction(path); loadAction(path);
@@ -577,11 +577,7 @@ bool Manager::checkUnavailableModulesJson(json_t* rootJ) {


if (!pluginModuleSlugs.empty()) { if (!pluginModuleSlugs.empty()) {
// Ask user to open browser // Ask user to open browser
std::string msg = "This patch includes modules that are not installed:";
msg += "\n\n";
msg += string::join(pluginModuleSlugs, "\n");
msg += "\n\n";
msg += "Show missing modules on the VCV Library?";
std::string msg = string::f(string::translate("patch.unavailableModules"), string::join(pluginModuleSlugs, "\n"));
if (osdialog_message(OSDIALOG_WARNING, OSDIALOG_YES_NO, msg.c_str())) { if (osdialog_message(OSDIALOG_WARNING, OSDIALOG_YES_NO, msg.c_str())) {
std::string url = "https://library.vcvrack.com/?modules="; std::string url = "https://library.vcvrack.com/?modules=";
url += string::join(pluginModuleSlugs, ","); url += string::join(pluginModuleSlugs, ",");


+ 3
- 1
src/plugin/Model.cpp View File

@@ -198,7 +198,9 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
} }


// Favorite // Favorite
std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : "";
std::string favoriteRightText;
if (inBrowser)
favoriteRightText = widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("key.click");
if (isFavorite()) if (isFavorite())
favoriteRightText += " " CHECKMARK_STRING; favoriteRightText += " " CHECKMARK_STRING;
menu->addChild(createMenuItem(string::translate("Model.favorite"), favoriteRightText, menu->addChild(createMenuItem(string::translate("Model.favorite"), favoriteRightText,


+ 4
- 4
src/ui/TextField.cpp View File

@@ -360,25 +360,25 @@ void TextField::createContextMenu() {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();


TextFieldCutItem* cutItem = new TextFieldCutItem; TextFieldCutItem* cutItem = new TextFieldCutItem;
cutItem->text = "Cut";
cutItem->text = string::translate("TextField.cut");
cutItem->rightText = widget::getKeyCommandName(GLFW_KEY_X, RACK_MOD_CTRL); cutItem->rightText = widget::getKeyCommandName(GLFW_KEY_X, RACK_MOD_CTRL);
cutItem->textField = this; cutItem->textField = this;
menu->addChild(cutItem); menu->addChild(cutItem);


TextFieldCopyItem* copyItem = new TextFieldCopyItem; TextFieldCopyItem* copyItem = new TextFieldCopyItem;
copyItem->text = "Copy";
copyItem->text = string::translate("TextField.copy");
copyItem->rightText = widget::getKeyCommandName(GLFW_KEY_C, RACK_MOD_CTRL); copyItem->rightText = widget::getKeyCommandName(GLFW_KEY_C, RACK_MOD_CTRL);
copyItem->textField = this; copyItem->textField = this;
menu->addChild(copyItem); menu->addChild(copyItem);


TextFieldPasteItem* pasteItem = new TextFieldPasteItem; TextFieldPasteItem* pasteItem = new TextFieldPasteItem;
pasteItem->text = "Paste";
pasteItem->text = string::translate("TextField.paste");
pasteItem->rightText = widget::getKeyCommandName(GLFW_KEY_V, RACK_MOD_CTRL); pasteItem->rightText = widget::getKeyCommandName(GLFW_KEY_V, RACK_MOD_CTRL);
pasteItem->textField = this; pasteItem->textField = this;
menu->addChild(pasteItem); menu->addChild(pasteItem);


TextFieldSelectAllItem* selectAllItem = new TextFieldSelectAllItem; TextFieldSelectAllItem* selectAllItem = new TextFieldSelectAllItem;
selectAllItem->text = "Select all";
selectAllItem->text = string::translate("TextField.selectAll");
selectAllItem->rightText = widget::getKeyCommandName(GLFW_KEY_A, RACK_MOD_CTRL); selectAllItem->rightText = widget::getKeyCommandName(GLFW_KEY_A, RACK_MOD_CTRL);
selectAllItem->textField = this; selectAllItem->textField = this;
menu->addChild(selectAllItem); menu->addChild(selectAllItem);


+ 1
- 0
src/widget/event.cpp View File

@@ -17,6 +17,7 @@ std::string getKeyName(int key) {
// glfwGetKeyName overrides // glfwGetKeyName overrides
switch (key) { switch (key) {
case GLFW_KEY_SPACE: return string::translate("key.space"); case GLFW_KEY_SPACE: return string::translate("key.space");
case GLFW_KEY_MINUS: return string::translate("key.minus");
} }


// Printable characters // Printable characters


+ 84
- 7
translations/en.json View File

@@ -2,6 +2,7 @@
"language": "English", "language": "English",
"translators": "", "translators": "",
"key.space": "Space", "key.space": "Space",
"key.minus": "Minus",
"key.escape": "Escape", "key.escape": "Escape",
"key.enter": "Enter", "key.enter": "Enter",
"key.tab": "Tab", "key.tab": "Tab",
@@ -19,6 +20,12 @@
"key.ctrl": "Ctrl", "key.ctrl": "Ctrl",
"key.shift": "Shift", "key.shift": "Shift",
"key.alt": "Alt", "key.alt": "Alt",
"key.click": "Click",
"key.rightClick": "Right-click",
"key.middleClick": "Middle-click",
"key.doubleClick": "Double-click",
"key.drag": "Drag",
"key.clickDrag": "Click+Drag",
"tag.Arpeggiator": "Arpeggiator", "tag.Arpeggiator": "Arpeggiator",
"tag.Attenuator": "Attenuator", "tag.Attenuator": "Attenuator",
"tag.Blank": "Blank", "tag.Blank": "Blank",
@@ -259,13 +266,11 @@
"Browser.allBrands": "All brands", "Browser.allBrands": "All brands",
"Browser.brand": "Brand", "Browser.brand": "Brand",
"Browser.allTags": "All tags", "Browser.allTags": "All tags",
"Browser.tagsSelectMultiple": "click to select multiple",
"Browser.tagsSelectMultiple": " to select multiple",
"Browser.tags": "Tags", "Browser.tags": "Tags",
"ParamWidget.history.setParam": "set parameter", "ParamWidget.history.setParam": "set parameter",
"ParamWidget.initialize": "Initialize", "ParamWidget.initialize": "Initialize",
"ParamWidget.doubleClick": "Double-click",
"ParamWidget.fine": "Fine adjust", "ParamWidget.fine": "Fine adjust",
"ParamWidget.fineDrag": "drag",
"ParamWidget.unmap": "Unmap", "ParamWidget.unmap": "Unmap",
"ParamWidget.history.reset": "reset parameter", "ParamWidget.history.reset": "reset parameter",
"PortWidget.from": "From ", "PortWidget.from": "From ",
@@ -275,13 +280,85 @@
"PortWidget.cableId": "ID: %ld", "PortWidget.cableId": "ID: %ld",
"PortWidget.setColor": "Set color", "PortWidget.setColor": "Set color",
"PortWidget.deleteTopCable": "Delete top cable", "PortWidget.deleteTopCable": "Delete top cable",
"PortWidget.click": "click",
"PortWidget.cloneTopCable": "Duplicate top cable", "PortWidget.cloneTopCable": "Duplicate top cable",
"PortWidget.createCableTop": "Create cable on top", "PortWidget.createCableTop": "Create cable on top",
"PortWidget.drag": "drag",
"PortWidget.createCable": "Create cable: ", "PortWidget.createCable": "Create cable: ",
"PortWidget.clickDrag": "Click+drag",
"PortWidget.grabCable": " to grab cable", "PortWidget.grabCable": " to grab cable",
"PortWidget.allCables": "All cables", "PortWidget.allCables": "All cables",
"PortWidget.history.moveCable": "move cable"
"PortWidget.history.moveCable": "move cable",
"library.loggingIn": "Logging in...",
"library.noResponse": "No response from server",
"library.noToken": "No token in response",
"library.queryingUpdates": "Querying for updates...",
"library.queryAccountFailed": "Could not query user account",
"library.queryManifestsFailed": "Could not query plugin manifests",
"library.queryModulesFailed": "Could not query user's modules",
"patch.saveFailed": "Could not save patch: %s",
"patch.overwriteTemplate": "Overwrite template patch?",
"patch.saveTemplateFailed": "Could not save template patch: %s",
"patch.loadTemplateFailed": "Could not load system template patch, clearing rack: %s",
"patch.loadTemplateConfirm": "The current patch is unsaved. Clear it and start a new patch?",
"patch.loadFailed": "Could not load patch: %s",
"patch.loadConfirm": "The current patch is unsaved. Clear it and open a new patch?",
"patch.revertConfirm": "Revert patch to the last saved state?",
"patch.unavailableModules": "This patch includes modules that are not installed:\n\n%s\n\nShow missing modules on the VCV Library?",
"Switch.history.move": "move switch",
"Knob.history.move": "move knob",
"TextField.cut": "Cut",
"TextField.copy": "Copy",
"TextField.paste": "Paste",
"TextField.selectAll": "Select all",
"standalone.multipleInstances": "VCV Rack is already running. Multiple Rack instances are not supported.",
"standalone.resetSettings": "Reset settings to default?",
"standalone.resDir": "VCV Rack's resource directory \"%s\" does not exist. Make sure Rack is correctly installed and launched.",
"standalone.micPermission": "VCV Rack cannot access audio input because Microphone permission is blocked.\n\nGive permission to Rack by opening Apple's System Settings and enabling Privacy & Security > Microphone > %s.",
"standalone.crashed": "VCV Rack crashed during the last session, possibly due to a buggy module in your patch. Clear your patch and start over?",
"AudioDisplay.audioDriver": "Audio driver",
"AudioDisplay.driver": "Driver: ",
"AudioDisplay.noDriver": "No driver",
"AudioDisplay.noDevice": "No device",
"AudioDisplay.audioDevice": "Audio device",
"AudioDisplay.device": "Device: ",
"AudioDisplay.lockedByDevice": "Locked by device",
"AudioDisplay.sampleRate": "Sample rate",
"AudioDisplay.sampleRateColon": "Rate: ",
"AudioDisplay.blockSize": "Block size",
"AudioDisplay.blockSizeColon": "Block size: ",
"MidiDisplay.driver": "MIDI driver",
"MidiDisplay.noDriver": "No driver",
"MidiDisplay.device": "MIDI device",
"MidiDisplay.noDevice": "No device",
"MidiDisplay.channel": "MIDI channel",
"MidiDisplay.channel1": "Channel 1",
"midi.allChannels": "All channels",
"midi.channelNum": "Channel %d",
"TipWindow.addModule": "To add a module to your patch, right-click an empty rack space or press Enter. Then click and drag a module from the Module Browser into the desired rack space.\\n\\nTo select multiple modules, click and drag on empty rack space.",
"TipWindow.moveRack": "To move around your patch, use the scroll bars, drag while holding the middle mouse button, %s and drag, or hold the arrow keys. Arrow key movement speed can be adjusted by holding %s, %s, or %s+%s.\\n\\nTo zoom in and out, drag the Zoom slider in the View menu, hold %s and scroll, or press %s and %s.",
"TipWindow.fullscreen": "You can use Rack in fullscreen mode by selecting \u201cView > Fullscreen\u201c or pressing F11.\\n\\nIn fullscreen mode, the menu bar and scroll bars are hidden. This is ideal for screen recording with VCV Recorder.",
"TipWindow.fullscreenButton": "Get VCV Recorder",
"TipWindow.library": "You can browse thousands of modules on the VCV Library website.\\n\\nRegister for a VCV account, log into Rack using the Library menu, and browse the VCV Library to add or purchase modules. Keep all plugins up to date by clicking \u201cLibrary > Update all\u201d.",
"TipWindow.libraryButton": "VCV Library",
"TipWindow.donation": "Some developers of free plugins accept donations. Right-click your favorite module's panel and select \u201cInfo > Donate\u201d.\\n\\nYou can also donate via the module's VCV Library page.",
"TipWindow.daw": "Want to use VCV Rack in your DAW? VCV Rack Pro is available for VST2, VST3, Audio Unit, and CLAP hosts.\\n\\nSupported DAWs include Ableton Live, Cubase, FL Studio, Reason, Bitwig, Reaper, Mixbus, Studio One, Cakewalk, Logic Pro, and GarageBand.",
"TipWindow.learnMore": "Learn more",
"TipWindow.manual": "You can learn more about VCV Rack by browsing the official manual.",
"TipWindow.manualButton": "VCV Rack manual",
"TipWindow.twitter": "Follow VCV Rack on Twitter for new module announcements, development news, and featured artists/music.",
"TipWindow.twitterHandle": "Twitter @vcvrack",
"TipWindow.polyphony": "Patch cables in Rack can carry up to 16 signals. You can use this ability to build polyphonic patches using modules having the \u201cPolyphonic\u201d tag. Cables carrying more than 1 signal appear thicker than normal cables. To try out polyphony, add the VCV MIDI-to-CV module to your patch, right-click its panel, and select your desired number of polyphonic channels.",
"TipWindow.polyphonyButton": "Learn more about polyphony in VCV Rack",
"TipWindow.develop": "Know C++ programming and want to create your own modules for Rack? Developing Rack modules is a great way to learn digital signal processing and quickly test your ideas with an easy-to-learn platform.\\n\\nDownload the Rack SDK and follow the development tutorial to get started.",
"TipWindow.developButton": "Plugin Development Tutorial",
"TipWindow.moduleManual": "Wondering how to use a particular module? Right-click its panel and choose \u201cInfo > User manual\u201d.\\n\\nYou can also open the module's Info menu to view the module's tags, website, VCV Library page, and changelog, if available.",
"TipWindow.modularGrid": "Did you know that the VCV Library is integrated with ModularGrid? If a module is available as a hardware Eurorack module, right-click its panel and choose \u201cInfo > ModularGrid\u201d, or click the \u201cModularGrid\u201d link on its VCV Library page.\\n\\nOn ModularGrid.net, search for the VCV logo on certain module's entry pages.",
"TipWindow.modularGridButton": "Example: Grayscale Permutation on ModularGrid",
"TipWindow.menuKeepOpen": "When any context menu is open, you can %s a menu item to keep the menu open. This can be useful when browsing module presets or settings.",
"TipWindow.welcome": "Welcome to %s",
"TipWindow.startup": "Show tips at startup",
"TipWindow.previous": "Previous",
"TipWindow.next": "Next",
"TipWindow.close": "Close",
"PortInfo.input": "%s input",
"PortInfo.output": "%s output",
"ModuleLightWidget.light": "%s light"
} }

Loading…
Cancel
Save