Skip to content

Commit

Permalink
Add proper translation UI
Browse files Browse the repository at this point in the history
  • Loading branch information
wheremyfoodat committed Dec 4, 2024
1 parent b4d212c commit 59016c2
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 197 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE)

set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp
src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp src/panda_qt/mappings.cpp
src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp
src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp src/panda_qt/translations.cpp
)
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp
include/panda_qt/config_window.hpp include/panda_qt/text_editor.hpp include/panda_qt/cheats_window.hpp
Expand Down Expand Up @@ -701,8 +701,8 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE)
docs/img/rnap_icon.png docs/img/rcow_icon.png docs/img/skyemu_icon.png
)

set(QT_TRANSLATIONS "${PROJECT_SOURCE_DIR}/docs/translations")
file(GLOB_RECURSE TRANSLATIONS_TS ${QT_TRANSLATIONS}/*.ts)
# Translation files in Qt's .ts format. Will be converted into binary files and embedded into the executable
set(TRANSLATIONS_TS docs/translations/en.ts docs/translations/el.ts)

set_source_files_properties(${TRANSLATIONS_TS} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
qt_add_translation(TRANSLATIONS_QM ${TRANSLATIONS_TS})
Expand Down
203 changes: 114 additions & 89 deletions docs/translations/el.ts

Large diffs are not rendered by default.

174 changes: 100 additions & 74 deletions docs/translations/en.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions include/frontend_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct FrontendSettings {

Theme theme = Theme::Dark;
WindowIcon icon = WindowIcon::Rpog;
std::string language = "en";

static Theme themeFromString(std::string inString);
static const char* themeToString(Theme theme);
Expand Down
2 changes: 2 additions & 0 deletions include/panda_qt/config_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class ConfigWindow : public QDialog {
void setTheme(FrontendSettings::Theme theme);
void setIcon(FrontendSettings::WindowIcon icon);

QComboBox* createLanguageSelect();

public:
ConfigWindow(ConfigCallback configCallback, MainWindowCallback windowCallback, const EmulatorConfig& config, QWidget* parent = nullptr);
~ConfigWindow();
Expand Down
2 changes: 2 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ void EmulatorConfig::load() {

frontendSettings.theme = FrontendSettings::themeFromString(toml::find_or<std::string>(ui, "Theme", "dark"));
frontendSettings.icon = FrontendSettings::iconFromString(toml::find_or<std::string>(ui, "WindowIcon", "rpog"));
frontendSettings.language = toml::find_or<std::string>(ui, "Language", "en");
}
}
}
Expand Down Expand Up @@ -202,6 +203,7 @@ void EmulatorConfig::save() {

data["UI"]["Theme"] = std::string(FrontendSettings::themeToString(frontendSettings.theme));
data["UI"]["WindowIcon"] = std::string(FrontendSettings::iconToString(frontendSettings.icon));
data["UI"]["Language"] = frontendSettings.language;

std::ofstream file(path, std::ios::out);
file << data;
Expand Down
5 changes: 4 additions & 1 deletion src/panda_qt/config_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win

// Set the window title of the main window appropriately if we enable showing the app version on the window
if (config.windowSettings.showAppVersion) {
getMainWindow()->setWindowTitle("Alber v" PANDA3DS_VERSION);
getMainWindow()->setWindowTitle(tr("Alber v%1").arg(PANDA3DS_VERSION));
}

// Initialize the widget list and the widget container widgets
Expand Down Expand Up @@ -96,6 +96,9 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win
});
guiLayout->addRow(tr("Window icon"), iconSelect);

QComboBox* languageSelect = createLanguageSelect();
guiLayout->addRow(tr("Language"), languageSelect);

QCheckBox* showAppVersion = new QCheckBox(tr("Show version on window title"));
showAppVersion->setChecked(config.windowSettings.showAppVersion);
connect(showAppVersion, &QCheckBox::toggled, this, [&](bool checked) {
Expand Down
32 changes: 2 additions & 30 deletions src/panda_qt/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <QDesktopServices>
#include <QFileDialog>
#include <QString>
#include <QTranslator>
#include <cmath>
#include <cstdio>
#include <fstream>
Expand All @@ -15,6 +14,8 @@
#include "version.hpp"

MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()) {
emu = new Emulator();

loadTranslation();
setWindowTitle(tr("Alber"));

Expand Down Expand Up @@ -77,7 +78,6 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
auto aboutAction = aboutMenu->addAction(tr("About Panda3DS"));
connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutMenu);

emu = new Emulator();
emu->setOutputSize(screen->surfaceWidth, screen->surfaceHeight);

// Set up misc objects
Expand Down Expand Up @@ -680,32 +680,4 @@ void MainWindow::setupControllerSensors(SDL_GameController* controller) {
if (haveAccelerometer) {
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
}
}

void MainWindow::loadTranslation() {
// TODO: This should become a member variable when we allow changing language at runtime.
QTranslator* translator = nullptr;

auto language = QString::fromStdString("el");
const QString baseDir = QStringLiteral(":/translations");
QString basePath = QStringLiteral("%1/%2.qm").arg(baseDir).arg(language);

if (QFile::exists(basePath)) {
if (translator != nullptr) {
qApp->removeTranslator(translator);
}

translator = new QTranslator(qApp);
if (!translator->load(basePath)) {
QMessageBox::warning(
nullptr, QStringLiteral("Translation Error"),
QStringLiteral("Failed to find load translation file for '%1':\n%2").arg(language).arg(basePath)
);
delete translator;
} else {
qApp->installTranslator(translator);
}
} else {
printf("Language file %s does not exist\n", basePath.toStdString().c_str());
}
}
91 changes: 91 additions & 0 deletions src/panda_qt/translations.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <QFile>
#include <QTranslator>
#include <array>
#include <cstdio>

#include "panda_qt/config_window.hpp"
#include "panda_qt/main_window.hpp"

void MainWindow::loadTranslation() {
// TODO: This should become a member variable when we allow changing language at runtime.
QTranslator* translator = nullptr;

// Fetch the .qm file for our language and load it
auto language = QString::fromStdString(emu->getConfig().frontendSettings.language);
const QString baseDir = QStringLiteral(":/translations");
const QString basePath = QStringLiteral("%1/%2.qm").arg(baseDir).arg(language);

if (QFile::exists(basePath)) {
if (translator != nullptr) {
qApp->removeTranslator(translator);
}

translator = new QTranslator(qApp);
if (!translator->load(basePath)) {
QMessageBox::warning(
nullptr, QStringLiteral("Translation Error"),
QStringLiteral("Failed to find load translation file for '%1':\n%2").arg(language).arg(basePath)
);
delete translator;
} else {
qApp->installTranslator(translator);
}
} else {
printf("Language file %s does not exist. Defaulting to English\n", basePath.toStdString().c_str());
}
}

struct LanguageInfo {
QString name; // Full name of the language (for example "English (US)")
const char* code; // ISO 639 language code (for example "en_us")

explicit LanguageInfo(const QString& name, const char* code) : name(name), code(code) {}
};

// List of languages in the order they should appear in the menu
// Please keep this list mostly in alphabetical order.
// Also, for Unicode characters in language names, use Unicode keycodes instead of writing out the name,
// as some compilers/toolchains may not enjoy Unicode in source files.
static std::array<LanguageInfo, 2> languages = {
LanguageInfo(QStringLiteral(u"English"), "en"), // English
LanguageInfo(QStringLiteral(u"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"), "el"), // Greek
};

QComboBox* ConfigWindow::createLanguageSelect() {
QComboBox* select = new QComboBox();

for (usize i = 0; i < languages.size(); i++) {
const auto& lang = languages[i];
select->addItem(lang.name);

if (config.frontendSettings.language == lang.code) {
select->setCurrentIndex(i);
}
}

connect(select, &QComboBox::currentIndexChanged, this, [&](int index) {
const QString baseDir = QStringLiteral(":/translations");
const QString basePath = QStringLiteral("%1/%2.qm").arg(baseDir).arg(languages[index].code);

if (QFile::exists(basePath)) {
config.frontendSettings.language = languages[index].code;
updateConfig();

QMessageBox messageBox(
QMessageBox::Icon::Information, tr("Language change successful"),
tr("Restart Panda3DS for the new language to be used.")
);

messageBox.exec();
} else {
QMessageBox messageBox(
QMessageBox::Icon::Warning, tr("Language change failed"),
tr("The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code...")
);

messageBox.exec();
}
});

return select;
}

0 comments on commit 59016c2

Please sign in to comment.