Skip to content

Commit c078ecb

Browse files
committed
GUI - Add UI language option
1 parent e4ae9ac commit c078ecb

File tree

12 files changed

+511
-36
lines changed

12 files changed

+511
-36
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ app/gui/qt/moc_mainwindow.cpp
6161
app/gui/qt/moc_sonicpiudpserver.cpp
6262
app/gui/qt/qrc_SonicPi.cpp
6363
app/gui/qt/utils/ruby_help.h
64-
app/gui/qt/help/*.html
64+
app/gui/qt/utils/lang_list.h
65+
app/gui/qt/help
6566
app/gui/qt/help_files.qrc
6667
app/gui/qt/lang/*.qm
6768
app/gui/qt/qrc_help_files.cpp

app/gui/qt/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,15 @@ set(QT_SOURCES
101101
set(SOURCES
102102
${QTAPP_ROOT}/main.cpp
103103
${QTAPP_ROOT}/utils/scintilla_api.cpp
104+
${QTAPP_ROOT}/utils/sonic_pi_i18n.cpp
104105
${QTAPP_ROOT}/widgets/sonicpilog.cpp
105106
${QTAPP_ROOT}/widgets/sonicpilog.h
106107
${QTAPP_ROOT}/widgets/sonicpicontext.cpp
107108
${QTAPP_ROOT}/widgets/sonicpicontext.h
108109
${QTAPP_ROOT}/utils/scintilla_api.h
110+
${QTAPP_ROOT}/utils/sonic_pi_i18n.h
109111
${QTAPP_ROOT}/utils/ruby_help.h
112+
${QTAPP_ROOT}/utils/lang_list.h
110113
${QTAPP_ROOT}/model/settings.h
111114
)
112115

app/gui/qt/main.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
// notice is included.
1212
//++
1313

14+
#include <iostream>
15+
1416
#include <QApplication>
1517
#include <QSplashScreen>
1618
#include <QPixmap>
1719
#include <QBitmap>
1820
#include <QLabel>
19-
#include <QTranslator>
2021
#include <QLibraryInfo>
2122

2223
#include "mainwindow.h"
@@ -35,7 +36,7 @@
3536

3637
int main(int argc, char *argv[])
3738
{
38-
39+
std::cout << "Starting Sonic Pi..." << std::endl;
3940
#ifndef Q_OS_MAC
4041
Q_INIT_RESOURCE(SonicPi);
4142
#endif
@@ -49,16 +50,6 @@ int main(int argc, char *argv[])
4950

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

52-
QString systemLocale = QLocale::system().uiLanguages()[0].replace("-", "_");
53-
54-
QTranslator qtTranslator;
55-
qtTranslator.load("qt_" + systemLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
56-
app.installTranslator(&qtTranslator);
57-
58-
QTranslator translator;
59-
bool i18n = translator.load(QLatin1String("sonic-pi_") + systemLocale, QLatin1String(":/lang")) || systemLocale.startsWith("en") || systemLocale == "C";
60-
app.installTranslator(&translator);
61-
6253
app.setApplicationName(QObject::tr("Sonic Pi"));
6354
app.setStyle("gtk");
6455

@@ -75,7 +66,7 @@ int main(int argc, char *argv[])
7566
splash->show();
7667
splash->repaint();
7768
app.processEvents();
78-
MainWindow mainWin(app, i18n, splash);
69+
MainWindow mainWin(app, splash);
7970

8071
return app.exec();
8172
#elif _WIN32
@@ -109,7 +100,7 @@ int main(int argc, char *argv[])
109100
splash->show();
110101
splash->repaint();
111102
app.processEvents();
112-
MainWindow mainWin(app, i18n, splash);
103+
MainWindow mainWin(app, splash);
113104

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

142-
MainWindow mainWin(app, i18n, splashWindow);
133+
MainWindow mainWin(app, splashWindow);
143134
return app.exec();
144135

145136
#endif
146-
147137
}

app/gui/qt/mainwindow.cpp

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
#include "widgets/sonicpilexer.h"
5353
#include "widgets/sonicpiscintilla.h"
5454

55+
#include "utils/sonic_pi_i18n.h"
56+
5557
#include "utils/borderlesslinksproxystyle.h"
5658

5759
// OSC stuff
@@ -105,9 +107,9 @@ using namespace SonicPi;
105107
#endif
106108

107109
#ifdef Q_OS_MAC
108-
MainWindow::MainWindow(QApplication& app, bool i18n, QMainWindow* splash)
110+
MainWindow::MainWindow(QApplication& app, QMainWindow* splash)
109111
#else
110-
MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
112+
MainWindow::MainWindow(QApplication& app, QSplashScreen* splash)
111113
#endif
112114
{
113115
app.installEventFilter(this);
@@ -118,9 +120,6 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
118120

119121
this->piSettings = new SonicPiSettings();
120122

121-
this->splash = splash;
122-
this->i18n = i18n;
123-
124123
#ifdef QT_OLD_API
125124
sonicPiOSCServer = NULL;
126125
#else
@@ -153,7 +152,6 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
153152
version_num = 0;
154153
latest_version_num = 0;
155154
this->splash = splash;
156-
this->i18n = i18n;
157155
#ifdef QT_OLD_API
158156
guiID = QUuid::createUuid().toString();
159157
#endif
@@ -163,6 +161,10 @@ MainWindow::MainWindow(QApplication& app, bool i18n, QSplashScreen* splash)
163161
initPaths();
164162

165163
bool startupOK = false;
164+
this->sonicPii18n = new SonicPii18n(rootPath());
165+
this->ui_language = sonicPii18n->determineUILanguage(piSettings->language);
166+
std::cout << "Using language: " << ui_language.toUtf8().constData() << std::endl;
167+
this->i18n = sonicPii18n->loadTranslations(ui_language);
166168

167169
#ifdef QT_OLD_API
168170
// Clear out old tasks from previous sessions if they still exist
@@ -579,7 +581,8 @@ void MainWindow::setupWindowStructure()
579581
prefsWidget->setAllowedAreas(Qt::RightDockWidgetArea);
580582
prefsWidget->setFeatures(QDockWidget::DockWidgetClosable);
581583

582-
settingsWidget = new SettingsWidget(server_osc_cues_port, piSettings, this);
584+
settingsWidget = new SettingsWidget(server_osc_cues_port, i18n, piSettings, sonicPii18n, this);
585+
connect(settingsWidget, SIGNAL(uiLanguageChanged(QString)), this, SLOT(changeUILanguage(QString)));
583586
connect(settingsWidget, SIGNAL(volumeChanged(int)), this, SLOT(changeSystemPreAmp(int)));
584587
connect(settingsWidget, SIGNAL(mixerSettingsChanged()), this, SLOT(mixerSettingsChanged()));
585588
connect(settingsWidget, SIGNAL(midiSettingsChanged()), this, SLOT(toggleMidi()));
@@ -2179,6 +2182,43 @@ void MainWindow::changeSystemPreAmp(int val, int silent)
21792182
statusBar()->showMessage(tr("Updating System Volume..."), 2000);
21802183
}
21812184

2185+
// TODO: Implement real-time language switching
2186+
void MainWindow::changeUILanguage(QString lang) {
2187+
if (lang != piSettings->language) {
2188+
std::cout << "Current language: " << piSettings->language.toUtf8().constData() << std::endl;
2189+
std::cout << "New language selected: " << lang.toUtf8().constData() << std::endl;
2190+
QString old_lang = sonicPii18n->getNativeLanguageName(piSettings->language);
2191+
QString new_lang = sonicPii18n->getNativeLanguageName(lang);
2192+
2193+
// Load new language
2194+
//QString language = sonicPii18n->determineUILanguage(lang);
2195+
//sonicPii18n->loadTranslations(language);
2196+
//QString title_new = tr("Updated the UI language from %s to %s").arg();
2197+
2198+
QMessageBox msgBox(this);
2199+
msgBox.setText(QString(tr("You've selected a new language: %1")).arg(new_lang));
2200+
msgBox.setInformativeText(tr("Do you want to apply this language?\nApplying the new language will restart Sonic Pi."));
2201+
QPushButton *restartButton = msgBox.addButton(tr("Apply and Restart"), QMessageBox::ActionRole);
2202+
QPushButton *dismissButton = msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole);
2203+
msgBox.setDefaultButton(restartButton);
2204+
msgBox.setIcon(QMessageBox::Information);
2205+
msgBox.exec();
2206+
2207+
if (msgBox.clickedButton() == (QAbstractButton*)restartButton) {
2208+
piSettings->language = lang;
2209+
writeSettings();
2210+
restartApp();
2211+
//statusBar()->showMessage(tr("Updated UI language setting, please restart Sonic Pi to apply it"), 2000);
2212+
} else if (msgBox.clickedButton() == (QAbstractButton*)dismissButton) {
2213+
// Don't apply the new language settings
2214+
settingsWidget->updateSelectedUILanguage(piSettings->language);
2215+
}
2216+
2217+
// Load previously set language
2218+
//sonicPii18n->loadTranslations(ui_language);
2219+
}
2220+
}
2221+
21822222
void MainWindow::changeScopeKindVisibility(QString name)
21832223
{
21842224
foreach (QAction* action, scopeKindVisibilityMenu->actions())
@@ -3500,6 +3540,8 @@ void MainWindow::readSettings()
35003540
QSettings settings(QSettings::IniFormat, QSettings::UserScope, "sonic-pi.net", "gui-settings");
35013541

35023542
// Read in preferences from previous session
3543+
piSettings->language = settings.value("prefs/language", "system_locale").toString();
3544+
35033545
piSettings->show_buttons = settings.value("prefs/show-buttons", true).toBool();
35043546
piSettings->show_tabs = settings.value("prefs/show-tabs", true).toBool();
35053547
piSettings->show_log = settings.value("prefs/show-log", true).toBool();
@@ -3549,6 +3591,7 @@ void MainWindow::writeSettings()
35493591
{
35503592
std::cout << "[GUI] - writing settings" << std::endl;
35513593
QSettings settings(QSettings::IniFormat, QSettings::UserScope, "sonic-pi.net", "gui-settings");
3594+
settings.setValue("prefs/language", piSettings->language);
35523595
settings.setValue("pos", pos());
35533596
settings.setValue("size", size());
35543597
settings.setValue("first_time", 0);
@@ -3732,6 +3775,31 @@ void MainWindow::onExitCleanup()
37323775
#endif
37333776
}
37343777

3778+
void MainWindow::restartApp() {
3779+
QApplication* app = dynamic_cast<QApplication*>(parent());
3780+
statusBar()->showMessage(tr("Restarting Sonic Pi..."), 10000);
3781+
// Save settings and perform some cleanup
3782+
writeSettings();
3783+
onExitCleanup();
3784+
sleep(1);
3785+
std::cout << "Performing application restart... please wait..." << std::endl;
3786+
//this->hide(); // So it doesn't look like the app's frozen or crashed
3787+
sleep(4); // Allow cleanup to complete
3788+
// Create new process
3789+
QStringList args = qApp->arguments();
3790+
args.removeFirst();
3791+
QProcess process;
3792+
bool restart_success = process.startDetached(qApp->arguments()[0], args);
3793+
if (restart_success) {
3794+
std::cout << "Successfully restarted sonic-pi" << std::endl;
3795+
} else {
3796+
std::cout << "Failed to restart sonic-pi" << std::endl;
3797+
}
3798+
// Quit
3799+
app->exit(0);
3800+
exit(0);
3801+
}
3802+
37353803
#ifdef QT_OLD_API
37363804
void MainWindow::cleanupRunningProcesses()
37373805
{

app/gui/qt/mainwindow.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <vector>
1818
#include <memory>
1919

20+
2021
#include <QDate>
2122
#include <QMainWindow>
2223
#include <QFuture>
@@ -70,6 +71,7 @@ class InfoWidget;
7071
class SettingsWidget;
7172
class Scope;
7273
class ScintillaAPI;
74+
class SonicPii18n;
7375
class SonicPiLog;
7476
class SonicPiScintilla;
7577
class SonicPiTheme;
@@ -94,9 +96,9 @@ class MainWindow : public QMainWindow
9496

9597
public:
9698
#if defined(Q_OS_MAC)
97-
MainWindow(QApplication &ref, bool i18n, QMainWindow* splash);
99+
MainWindow(QApplication &ref, QMainWindow* splash);
98100
#else
99-
MainWindow(QApplication &ref, bool i18n, QSplashScreen* splash);
101+
MainWindow(QApplication &ref, QSplashScreen* splash);
100102
#endif
101103

102104
SonicPiLog* GetOutputPane() const;
@@ -123,6 +125,8 @@ class MainWindow : public QMainWindow
123125

124126
bool loaded_workspaces;
125127
QString hash_salt;
128+
QString ui_language;
129+
126130

127131
protected:
128132
void closeEvent(QCloseEvent *event);
@@ -137,6 +141,7 @@ class MainWindow : public QMainWindow
137141

138142
private slots:
139143

144+
void changeUILanguage(QString lang);
140145
void updateContext(int line, int index);
141146
void updateContextWithCurrentWs();
142147
void docLinkClicked(const QUrl &url);
@@ -182,6 +187,7 @@ class MainWindow : public QMainWindow
182187
void help();
183188
void toggleHelpIcon();
184189
void onExitCleanup();
190+
void restartApp();
185191
void toggleRecording();
186192
void toggleRecordingOnIcon();
187193
void changeSystemPreAmp(int val, int silent=0);
@@ -351,10 +357,12 @@ class MainWindow : public QMainWindow
351357
QString rootPath();
352358

353359
void addUniversalCopyShortcuts(QTextEdit *te);
360+
void updateTranslatedUIText();
354361

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

357364
SonicPiSettings *piSettings;
365+
SonicPii18n *sonicPii18n;
358366

359367
#ifdef QT_OLD_API
360368
QFuture<void> osc_thread, server_thread;
@@ -458,4 +466,3 @@ class MainWindow : public QMainWindow
458466
QSet<QString> cuePaths;
459467

460468
};
461-

app/gui/qt/model/settings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class SonicPiSettings {
2424
QString midi_default_channel_str;
2525

2626
// EditorSettings
27+
QString language;
2728
bool auto_indent_on_run;
2829
bool show_line_numbers;
2930
bool show_log;

app/gui/qt/utils/lang_list.tmpl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//--
2+
// This file is part of Sonic Pi: http://sonic-pi.net
3+
// Full project source: https://github.com/samaaron/sonic-pi
4+
// License: https://github.com/samaaron/sonic-pi/blob/main/LICENSE.md
5+
//
6+
// Copyright 2020 by Sam Aaron (http://sam.aaron.name).
7+
// All rights reserved.
8+
//
9+
// Permission is granted for use, copying, modification, distribution,
10+
// and distribution of modified versions of this work as long as this
11+
// notice is included.
12+
//++
13+
14+
// AUTO-GENERATED-DOCS
15+
// Do not manually add any code below this comment
16+
// otherwise it may be removed

0 commit comments

Comments
 (0)