Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI: Add UI language option #2604

Merged
merged 22 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
46733ec
Synths winwood_lead, bass_foundation, bass_highend
Jan 12, 2021
985f289
Adjusted paths in synthdefs
Jan 12, 2021
c078ecb
GUI - Add UI language option
SunderB Jan 29, 2019
7c663da
GUI - Fix restartApp() on Windows; neaten and clean up changes made i…
SunderB Feb 14, 2021
759fa02
GUI - move language change message box handling from MainWindow to Se…
SunderB Feb 14, 2021
3c98ff1
Update .gitignore
SunderB Feb 14, 2021
0422ed1
GUI - Add function to test all found UI translations
SunderB Feb 14, 2021
687316d
GUI - Update native language names
SunderB Feb 14, 2021
1cbb2ef
GUI - Apply the current theme's background colour to message boxes
SunderB Feb 15, 2021
320d91f
GUI - Tweak 'predefined language name not found' warning
SunderB Feb 15, 2021
f01c901
GUI - Output language loading logs to gui.log
SunderB Feb 15, 2021
30ceabf
GUI - Show an error message when the selected language fails to load,…
SunderB Feb 15, 2021
1e287dd
GUI - Update native language names
SunderB Feb 15, 2021
74d19df
GUI - rename sonic_pi_i18n.cpp to sonicpi_i18n.cpp
SunderB Mar 11, 2021
fc7881e
GUI - Add language section to toolbar; move the language setting to i…
SunderB Mar 20, 2021
cee7fc0
GUI - Give the user the option whether or not to restart Sonic Pi whe…
SunderB Mar 21, 2021
0c1ea59
Merge pull request #2628 from level-xx/main
samaaron Apr 27, 2021
fa3961e
Merge branch 'dev' into patch-localeOption
SunderB Apr 27, 2021
a2b1b17
GUI: Fix some compilation errors from previous commit
SunderB Apr 27, 2021
9372da9
GUI: Ensure that the UI settings are saved before restarting Sonic Pi
SunderB Apr 27, 2021
2f61cba
GUI - Minor tweaks relating to the UI language option
SunderB Apr 28, 2021
767e3aa
Merge branch 'dev' into patch-localeOption
SunderB May 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ app/gui/qt/moc_mainwindow.cpp
app/gui/qt/moc_sonicpiudpserver.cpp
app/gui/qt/qrc_SonicPi.cpp
app/gui/qt/utils/ruby_help.h
app/gui/qt/utils/lang_list.h
app/gui/qt/help/*.html
app/gui/qt/help_files.qrc
app/gui/qt/lang/*.qm
Expand Down
3 changes: 3 additions & 0 deletions app/gui/qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,15 @@ set(QT_SOURCES
set(SOURCES
${QTAPP_ROOT}/main.cpp
${QTAPP_ROOT}/utils/scintilla_api.cpp
${QTAPP_ROOT}/utils/sonicpi_i18n.cpp
${QTAPP_ROOT}/widgets/sonicpilog.cpp
${QTAPP_ROOT}/widgets/sonicpilog.h
${QTAPP_ROOT}/widgets/sonicpicontext.cpp
${QTAPP_ROOT}/widgets/sonicpicontext.h
${QTAPP_ROOT}/utils/scintilla_api.h
${QTAPP_ROOT}/utils/sonicpi_i18n.h
${QTAPP_ROOT}/utils/ruby_help.h
${QTAPP_ROOT}/utils/lang_list.h
${QTAPP_ROOT}/model/settings.h
)

Expand Down
22 changes: 6 additions & 16 deletions app/gui/qt/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
// notice is included.
//++

#include <iostream>

#include <QApplication>
#include <QSplashScreen>
#include <QPixmap>
#include <QBitmap>
#include <QLabel>
#include <QTranslator>
#include <QLibraryInfo>

#include "mainwindow.h"
Expand All @@ -35,7 +36,7 @@

int main(int argc, char *argv[])
{

std::cout << "Starting Sonic Pi..." << std::endl;
#ifndef Q_OS_MAC
Q_INIT_RESOURCE(SonicPi);
#endif
Expand All @@ -49,16 +50,6 @@ int main(int argc, char *argv[])

qRegisterMetaType<SonicPiLog::MultiMessage>("SonicPiLog::MultiMessage");

QString systemLocale = QLocale::system().uiLanguages()[0].replace("-", "_");

QTranslator qtTranslator;
qtTranslator.load("qt_" + systemLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&qtTranslator);

QTranslator translator;
bool i18n = translator.load(QLatin1String("sonic-pi_") + systemLocale, QLatin1String(":/lang")) || systemLocale.startsWith("en") || systemLocale == "C";
app.installTranslator(&translator);

app.setApplicationName(QObject::tr("Sonic Pi"));
app.setStyle("gtk");

Expand All @@ -75,7 +66,7 @@ int main(int argc, char *argv[])
splash->show();
splash->repaint();
app.processEvents();
MainWindow mainWin(app, i18n, splash);
MainWindow mainWin(app, splash);

return app.exec();
#elif _WIN32
Expand Down Expand Up @@ -109,7 +100,7 @@ int main(int argc, char *argv[])
splash->show();
splash->repaint();
app.processEvents();
MainWindow mainWin(app, i18n, splash);
MainWindow mainWin(app, splash);

// Fix for full screen mode. See: https://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows
QWindowsWindowFunctions::setHasBorderInFullScreen(mainWin.windowHandle(), true);
Expand Down Expand Up @@ -139,9 +130,8 @@ int main(int argc, char *argv[])
splashWindow->show();
app.processEvents();

MainWindow mainWin(app, i18n, splashWindow);
MainWindow mainWin(app, splashWindow);
return app.exec();

#endif

}
107 changes: 102 additions & 5 deletions app/gui/qt/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
#include "widgets/sonicpilexer.h"
#include "widgets/sonicpiscintilla.h"

#include "utils/sonicpi_i18n.h"

#include "utils/borderlesslinksproxystyle.h"
#include "visualizer/scope_window.h"

Expand Down Expand Up @@ -89,9 +91,9 @@ using namespace std::chrono;
using namespace SonicPi;

#ifdef Q_OS_MAC
MainWindow::MainWindow(QApplication& app, bool i18n, QMainWindow* splash)
MainWindow::MainWindow(QApplication& app, QMainWindow* splash)
#else
MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
MainWindow::MainWindow(QApplication& app, QSplashScreen* splash)
#endif
{
app.installEventFilter(this);
Expand All @@ -103,7 +105,6 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
this->piSettings = new SonicPiSettings();

this->splash = splash;
this->i18n = i18n;

// API and Client
m_spClient = std::make_shared<QtAPIClient>(this);
Expand All @@ -126,7 +127,6 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
version_num = 0;
latest_version_num = 0;
this->splash = splash;
this->i18n = i18n;
QString settings_path = sonicPiConfigPath() + QDir::separator() + "gui-settings.ini";

gui_settings = new QSettings(settings_path, QSettings::IniFormat);
Expand All @@ -139,6 +139,19 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
m_spAPI->Init(rootPath().toStdString());
guiID = QString::fromStdString(m_spAPI->GetGuid());

this->sonicPii18n = new SonicPii18n(rootPath());
std::cout << "[GUI] - Language setting: " << piSettings->language.toUtf8().constData() << std::endl;
std::cout << "[GUI] - System language: " << QLocale::system().name().toStdString() << std::endl;
this->ui_language = sonicPii18n->determineUILanguage(piSettings->language);
std::cout << "[GUI] - Using language: " << ui_language.toUtf8().constData() << std::endl;
this->i18n = sonicPii18n->loadTranslations(ui_language);

if(i18n) {
std::cout << "[GUI] - translations available " << std::endl;
} else {
std::cout << "[GUI] - translations unavailable (using EN)" << std::endl;
}

std::cout << "[GUI] - hiding main window" << std::endl;
hide();

Expand Down Expand Up @@ -212,6 +225,11 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
toggleOSCServer(1);

app.setActiveWindow(tabs->currentWidget());

if (!i18n) {
showLanguageLoadingError();
}

showWelcomeScreen();
}

Expand Down Expand Up @@ -348,7 +366,8 @@ void MainWindow::setupWindowStructure()
prefsWidget->setAllowedAreas(Qt::RightDockWidgetArea);
prefsWidget->setFeatures(QDockWidget::DockWidgetClosable);

settingsWidget = new SettingsWidget(m_spAPI->GetPort(SonicPiPortId::server_osc_cues), piSettings, this);
settingsWidget = new SettingsWidget(m_spAPI->GetPort(SonicPiPortId::server_osc_cues), i18n, piSettings, sonicPii18n, this);
connect(settingsWidget, SIGNAL(restartApp()), this, SLOT(restartApp()));
connect(settingsWidget, SIGNAL(volumeChanged(int)), this, SLOT(changeSystemPreAmp(int)));
connect(settingsWidget, SIGNAL(mixerSettingsChanged()), this, SLOT(mixerSettingsChanged()));
connect(settingsWidget, SIGNAL(midiSettingsChanged()), this, SLOT(toggleMidi()));
Expand Down Expand Up @@ -1216,6 +1235,18 @@ void MainWindow::startupError(QString msg)
// TODO: Add format error to API
}

void MainWindow::showLanguageLoadingError() {
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(QString(tr("Failed to load translations for language: %1")).arg(sonicPii18n->getNativeLanguageName(this->ui_language)));
msgBox.setInformativeText(tr("Falling back to English. Sorry about this.") + "\n" + tr("Please consider reporting a bug at") + "\nhttp://github.com/sonic-pi-net/sonic-pi/issues");

QPushButton *okButton = msgBox.addButton(tr("OK"), QMessageBox::AcceptRole);
msgBox.setDefaultButton(okButton);

msgBox.exec();
}

void MainWindow::replaceBuffer(QString id, QString content, int line, int index, int first_line)
{
SonicPiScintilla* ws = filenameToWorkspace(id.toStdString());
Expand Down Expand Up @@ -2880,6 +2911,39 @@ void MainWindow::createToolBar()
viewMenu->addAction(focusHelpListingAct);
viewMenu->addAction(focusHelpDetailsAct);
viewMenu->addAction(focusErrorsAct);

languageMenu = menuBar()->addMenu(tr("Language"));
QStringList available_languages = sonicPii18n->getAvailableLanguages();

langActionGroup = new QActionGroup(this);
langActionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive);

QSignalMapper *signalMapper = new QSignalMapper(this);

for (size_t i = 0; i < available_languages.length(); i += 1) {
bool is_current_lang = (available_languages[i] == piSettings->language);

QAction *langAct = new QAction(sonicPii18n->getNativeLanguageName(available_languages[i]), this);
langAct->setCheckable(true);
langAct->setChecked(is_current_lang);

connect(langAct, SIGNAL(triggered()), signalMapper, SLOT(map()));
signalMapper->setMapping(langAct, i);

langActionGroup->addAction(langAct);
languageMenu->addAction(langAct);

if (i == 0) { // add separator after System language
languageMenu->addSeparator();
}
}

connect(signalMapper, SIGNAL(mappedInt(int)), settingsWidget, SLOT(updateUILanguage(int)));
connect(settingsWidget, SIGNAL(uiLanguageChanged(QString)), this, SLOT(updateSelectedUILanguageAction(QString)));
}

void MainWindow::updateSelectedUILanguageAction(QString lang) {
langActionGroup->actions()[sonicPii18n->getAvailableLanguages().indexOf(lang)]->setChecked(true);
}

QString MainWindow::readFile(QString name)
Expand Down Expand Up @@ -3074,6 +3138,7 @@ void MainWindow::readSettings()
std::cout << "[GUI] - reading settings" << std::endl;

// Read in preferences from previous session
piSettings->language = gui_settings->value("prefs/language", "system_language").toString();
piSettings->show_buttons = gui_settings->value("prefs/show-buttons", true).toBool();
piSettings->show_tabs = gui_settings->value("prefs/show-tabs", true).toBool();
piSettings->show_log = gui_settings->value("prefs/show-log", true).toBool();
Expand All @@ -3100,6 +3165,7 @@ void MainWindow::readSettings()
piSettings->show_scope_labels = gui_settings->value("prefs/scope/show-labels", false).toBool();
piSettings->show_cues = gui_settings->value("prefs/show_cues", true).toBool();
QString styleName = gui_settings->value("prefs/theme", "").toString();

piSettings->themeStyle = theme->themeNameToStyle(styleName);
piSettings->show_autocompletion = gui_settings->value("prefs/show-autocompletion", true).toBool();
piSettings->show_context = gui_settings->value("prefs/show-context", true).toBool();
Expand All @@ -3121,10 +3187,13 @@ void MainWindow::restoreScopeState(std::vector<QString> names)
void MainWindow::writeSettings()
{
std::cout << "[GUI] - writing settings" << std::endl;

gui_settings->setValue("pos", pos());
gui_settings->setValue("size", size());
gui_settings->setValue("first_time", 0);

gui_settings->setValue("prefs/language", piSettings->language);

gui_settings->setValue("prefs/midi-default-channel", piSettings->midi_default_channel);
gui_settings->setValue("prefs/midi-enable", piSettings->midi_enabled);
gui_settings->setValue("prefs/osc-public", piSettings->osc_public);
Expand Down Expand Up @@ -3172,6 +3241,9 @@ void MainWindow::writeSettings()
gui_settings->setValue("docsplitState", docsplit->saveState());
gui_settings->setValue("windowState", saveState());
gui_settings->setValue("windowGeom", saveGeometry());

// Force Qt to write the settings to the ini file
gui_settings->sync();
}

void MainWindow::loadFile(const QString& fileName, SonicPiScintilla*& text)
Expand Down Expand Up @@ -3261,6 +3333,31 @@ void MainWindow::onExitCleanup()
}
}

void MainWindow::restartApp() {
QApplication* app = dynamic_cast<QApplication*>(parent());
statusBar()->showMessage(tr("Restarting Sonic Pi..."), 10000);

// Save settings and perform some cleanup
writeSettings();
onExitCleanup();
std::cout << "Performing application restart..." << std::endl;

// Create new process
QStringList args = qApp->arguments();
args.removeFirst();
QProcess process;
bool restart_success = process.startDetached(qApp->arguments()[0], args);
if (restart_success) {
std::cout << "Successfully restarted sonic-pi" << std::endl;
} else {
std::cout << "Failed to restart sonic-pi" << std::endl;
}

// Quit
app->exit(0);
exit(0);
}

void MainWindow::heartbeatOSC()
{
// Message msg("/gui-heartbeat");
Expand Down
17 changes: 14 additions & 3 deletions app/gui/qt/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <vector>
#include <memory>


#include <QDate>
#include <QMainWindow>
#include <QFuture>
Expand All @@ -34,6 +35,7 @@
#include "config.h"

class QAction;
class QActionGroup;
class QMenu;
class QToolBar;
class QLineEdit;
Expand Down Expand Up @@ -67,6 +69,7 @@ class InfoWidget;
class SettingsWidget;
class Scope;
class ScintillaAPI;
class SonicPii18n;
class SonicPiLog;
class SonicPiScintilla;
class SonicPiTheme;
Expand All @@ -91,9 +94,9 @@ class MainWindow : public QMainWindow

public:
#if defined(Q_OS_MAC)
MainWindow(QApplication &ref, bool i18n, QMainWindow* splash);
MainWindow(QApplication &ref, QMainWindow* splash);
#else
MainWindow(QApplication &ref, bool i18n, QSplashScreen* splash);
MainWindow(QApplication &ref, QSplashScreen* splash);
#endif

SonicPiLog* GetOutputPane() const;
Expand All @@ -118,6 +121,8 @@ class MainWindow : public QMainWindow

bool loaded_workspaces;
QString hash_salt;
QString ui_language;


protected:
void closeEvent(QCloseEvent *event);
Expand All @@ -132,6 +137,7 @@ class MainWindow : public QMainWindow

private slots:

void updateSelectedUILanguageAction(QString lang);
void updateContext(int line, int index);
void updateContextWithCurrentWs();
void docLinkClicked(const QUrl &url);
Expand Down Expand Up @@ -178,6 +184,7 @@ class MainWindow : public QMainWindow
void help();
void toggleHelpIcon();
void onExitCleanup();
void restartApp();
void toggleRecording();
void toggleRecordingOnIcon();
void changeSystemPreAmp(int val, int silent=0);
Expand Down Expand Up @@ -229,6 +236,7 @@ class MainWindow : public QMainWindow
void splashClose();
void setMessageBoxStyle();
void startupError(QString msg);
void showLanguageLoadingError();
void tabNext();
void tabPrev();
void tabGoto(int index);
Expand Down Expand Up @@ -327,11 +335,13 @@ class MainWindow : public QMainWindow
QString rootPath();

void addUniversalCopyShortcuts(QTextEdit *te);
void updateTranslatedUIText();

QMenu *liveMenu, *codeMenu, *audioMenu, *displayMenu, *viewMenu, *ioMenu, *ioMidiInMenu, *ioMidiOutMenu, *ioMidiOutChannelMenu, *localIpAddressesMenu, *themeMenu, *scopeKindVisibilityMenu;
QMenu *liveMenu, *codeMenu, *audioMenu, *displayMenu, *viewMenu, *ioMenu, *ioMidiInMenu, *ioMidiOutMenu, *ioMidiOutChannelMenu, *localIpAddressesMenu, *themeMenu, *scopeKindVisibilityMenu, *languageMenu;

QSettings *gui_settings;
SonicPiSettings *piSettings;
SonicPii18n *sonicPii18n;

bool focusMode;
QCheckBox *startup_error_reported;
Expand Down Expand Up @@ -380,6 +390,7 @@ class MainWindow : public QMainWindow

QAction *exitAct, *runAct, *stopAct, *saveAsAct, *loadFileAct, *recAct, *textAlignAct, *textIncAct, *textDecAct, *scopeAct, *infoAct, *helpAct, *prefsAct, *focusEditorAct, *focusLogsAct, *focusContextAct, *focusCuesAct, *focusPreferencesAct, *focusHelpListingAct, *focusHelpDetailsAct, *focusErrorsAct, *showLineNumbersAct, *showAutoCompletionAct, *showContextAct, *audioSafeAct, *audioTimingGuaranteesAct, *enableExternalSynthsAct, *mixerInvertStereoAct, *mixerForceMonoAct, *midiEnabledAct, *enableOSCServerAct, *allowRemoteOSCAct, *showLogAct, *showCuesAct, *logAutoScrollAct, *logCuesAct, *logSynthsAct, *clearOutputOnRunAct, *autoIndentOnRunAct, *showButtonsAct, *showTabsAct, *fullScreenAct, *lightThemeAct, *darkThemeAct, *proLightThemeAct, *proDarkThemeAct, *highContrastThemeAct, *showScopeLabelsAct;
QShortcut *runSc, *stopSc, *saveAsSc, *loadFileSc, *recSc, *textAlignSc, *textIncSc, *textDecSc, *scopeSc, *infoSc, *helpSc, *prefsSc, *focusEditorSc, *focusLogsSc, *focusContextSc, *focusCuesSc, *focusPreferencesSc, *focusHelpListingSc, *focusHelpDetailsSc, *focusErrorsSc;
QActionGroup *langActionGroup;

SettingsWidget *settingsWidget;

Expand Down
Loading