Compare commits

...

9 Commits

Author SHA1 Message Date
fearlessTobi
d28af5097a Fix this shit up 2019-06-08 02:57:03 +02:00
fearlessTobi
0d567ac1cc yuzu: address some review comments and fix compilation in CI 2019-06-08 01:55:34 +02:00
fearlessTobi
85498975f2 yuzu: make tabbed config work with translations 2019-06-08 01:55:33 +02:00
zhupengfei
2cba8b3ab6 yuzu/configuration: fix language configuration issues and create UI tab
Cleans up the user interface by grouping relevant UI settings together.

Also see https://github.com/citra-emu/citra/pull/4398 for why we needed to fix issues with the translation feature.
2019-06-08 01:53:01 +02:00
wwylele
0d7547b46d README: add info about translation 2019-06-08 01:41:00 +02:00
wwylele
1de74afd63 fixup!citra_qt: load translation from resource 2019-06-08 01:41:00 +02:00
wwylele
c9969791b7 Travis, Appveyor: build with languages 2019-06-08 01:41:00 +02:00
wwylele
48ac1c2e67 cmake: generate translation file and add to resource for citra_qt 2019-06-08 01:41:00 +02:00
wwylele
9a8c4db441 citra_qt: load translation from resource 2019-06-08 01:40:59 +02:00
36 changed files with 369 additions and 156 deletions

2
.travis/linux-mingw/docker.sh Executable file → Normal file
View File

@@ -13,7 +13,7 @@ echo '' >> /bin/cmd
chmod +x /bin/cmd
mkdir build && cd build
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON
ninja
# Clean up the dirty hacks

2
.travis/linux/docker.sh Executable file → Normal file
View File

@@ -3,7 +3,7 @@
cd /yuzu
mkdir build && cd build
cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON
ninja
ccache -s

View File

@@ -10,7 +10,7 @@ export PATH="/usr/local/opt/ccache/libexec:$PATH"
# TODO: Build using ninja instead of make
mkdir build && cd build
cmake --version
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON
make -j4
ccache -s

View File

@@ -13,6 +13,7 @@ option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
@@ -255,6 +256,10 @@ if (ENABLE_QT)
if (YUZU_USE_QT_WEB_ENGINE)
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets ${QT_PREFIX_HINT})
endif ()
if (ENABLE_QT_TRANSLATION)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
endif()
endif()
# Platform-specific library requirements

View File

@@ -21,6 +21,8 @@ Most of the development happens on GitHub. It's also where [our central reposito
If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should as well contact any of the developers on Discord in order to know about the current state of the emulator.
If you want to contribute to the user interface translation, please checkout [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize the translation work there, and periodically upstream translation.
### Building
* __Windows__: [Windows Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Windows)

View File

@@ -44,7 +44,7 @@ before_build:
# redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning
cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0'
} else {
C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1"
C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON .. 2>&1"
}
- cd ..

3
dist/languages/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Ignore the source language file
en.ts

9
dist/languages/.tx/config vendored Normal file
View File

@@ -0,0 +1,9 @@
[main]
host = https://www.transifex.com
[yuzu.emulator]
file_filter = <lang>.ts
source_file = en.ts
source_lang = en
type = QT

1
dist/languages/README.md vendored Normal file
View File

@@ -0,0 +1 @@
This directory stores translation patches (TS files) for yuzu Qt frontend. This directory is linked with [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu), so you can update the translation by executing `tx pull -a`. If you want to contribute to the translation, please go the transifex link and submit your translation there. This directory on the main repo will be synchronized with transifex periodically. Do not directly open PRs on Github to modify the translation.

View File

@@ -27,8 +27,6 @@ add_executable(yuzu
configuration/configure_debug.h
configuration/configure_dialog.cpp
configuration/configure_dialog.h
configuration/configure_gamelist.cpp
configuration/configure_gamelist.h
configuration/configure_general.cpp
configuration/configure_general.h
configuration/configure_graphics.cpp
@@ -51,6 +49,8 @@ add_executable(yuzu
configuration/configure_per_general.h
configuration/configure_touchscreen_advanced.cpp
configuration/configure_touchscreen_advanced.h
configuration/configure_ui.cpp
configuration/configure_ui.h
configuration/configure_web.cpp
configuration/configure_web.h
debugger/graphics/graphics_breakpoint_observer.cpp
@@ -94,7 +94,6 @@ set(UIS
configuration/configure.ui
configuration/configure_audio.ui
configuration/configure_debug.ui
configuration/configure_gamelist.ui
configuration/configure_general.ui
configuration/configure_graphics.ui
configuration/configure_hotkeys.ui
@@ -106,6 +105,7 @@ set(UIS
configuration/configure_profile_manager.ui
configuration/configure_system.ui
configuration/configure_touchscreen_advanced.ui
configuration/configure_ui.ui
configuration/configure_web.ui
compatdb.ui
loading_screen.ui
@@ -120,6 +120,39 @@ file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
qt5_wrap_ui(UI_HDRS ${UIS})
if (ENABLE_QT_TRANSLATION)
set(YUZU_QT_LANGUAGES "${CMAKE_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
# Update source TS file if enabled
if (GENERATE_QT_TRANSLATION)
get_target_property(SRCS yuzu SOURCES)
qt5_create_translation(QM_FILES ${SRCS} ${UIS} ${YUZU_QT_LANGUAGES}/en.ts)
add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts)
endif()
# Find all TS files except en.ts
file(GLOB_RECURSE LANGUAGES_TS ${YUZU_QT_LANGUAGES}/*.ts)
list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts)
# Compile TS files to QM files
qt5_add_translation(LANGUAGES_QM ${LANGUAGES_TS})
# Build a QRC file from the QM file list
set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc)
file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n")
foreach (QM ${LANGUAGES_QM})
get_filename_component(QM_FILE ${QM} NAME)
file(APPEND ${LANGUAGES_QRC} "<file>${QM_FILE}</file>\n")
endforeach (QM)
file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>")
# Add the QRC file to package in all QM files
qt5_add_resources(LANGUAGES ${LANGUAGES_QRC})
else()
set(LANGUAGES)
endif()
target_sources(yuzu
PRIVATE
${COMPAT_LIST}
@@ -127,6 +160,7 @@ target_sources(yuzu
${THEMES}
${UI_HDRS}
${UIS}
${LANGUAGES}
)
if (APPLE)

View File

@@ -519,6 +519,8 @@ void Config::ReadPathValues() {
UISettings::values.game_directory_deepscan =
ReadSetting(QStringLiteral("gameListDeepScan"), false).toBool();
UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList();
UISettings::values.language =
ReadSetting(QStringLiteral("language"), QStringLiteral("")).toString();
qt_config->endGroup();
}
@@ -901,6 +903,7 @@ void Config::SavePathValues() {
WriteSetting(QStringLiteral("gameListDeepScan"), UISettings::values.game_directory_deepscan,
false);
WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files);
WriteSetting(QStringLiteral("language"), UISettings::values.language, QStringLiteral(""));
qt_config->endGroup();
}

View File

@@ -24,17 +24,11 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="selectorList">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
<property name="minimumWidth">
<number>150</number>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
<property name="maximumWidth">
<number>150</number>
</property>
</widget>
</item>
@@ -48,11 +42,6 @@
<string>General</string>
</attribute>
</widget>
<widget class="ConfigureGameList" name="gameListTab">
<attribute name="title">
<string>Game List</string>
</attribute>
</widget>
<widget class="ConfigureSystem" name="systemTab">
<attribute name="title">
<string>System</string>
@@ -93,6 +82,11 @@
<string>Web</string>
</attribute>
</widget>
<widget class="ConfigureUi" name="uiTab">
<attribute name="title">
<string>UI</string>
</attribute>
</widget>
</widget>
</item>
</layout>
@@ -150,9 +144,9 @@
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureGameList</class>
<class>ConfigureUi</class>
<extends>QWidget</extends>
<header>configuration/configure_gamelist.h</header>
<header>configuration/configure_ui.h</header>
<container>1</container>
</customwidget>
<customwidget>

View File

@@ -20,11 +20,11 @@ public:
void ApplyConfiguration();
void RetranslateUI();
void SetConfiguration();
private:
void UpdateAudioDevices(int sink_index);
void SetConfiguration();
void SetOutputSinkFromSinkID();
void SetAudioDeviceFromDeviceID();
void SetVolumeIndicatorText(int percentage);

View File

@@ -51,3 +51,7 @@ void ConfigureDebug::ApplyConfiguration() {
filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(filter);
}
void ConfigureDebug::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -19,8 +19,7 @@ public:
~ConfigureDebug() override;
void ApplyConfiguration();
private:
void RetranslateUI();
void SetConfiguration();
std::unique_ptr<Ui::ConfigureDebug> ui;

View File

@@ -17,9 +17,9 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
ui->hotkeysTab->Populate(registry);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
SetConfiguration();
PopulateSelectionList();
connect(ui->uiTab, &ConfigureUi::languageChanged, this, &ConfigureDialog::onLanguageChanged);
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs);
@@ -29,11 +29,20 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
ConfigureDialog::~ConfigureDialog() = default;
void ConfigureDialog::SetConfiguration() {}
void ConfigureDialog::SetConfiguration() {
ui->generalTab->SetConfiguration();
ui->uiTab->SetConfiguration();
ui->systemTab->SetConfiguration();
ui->inputTab->LoadConfiguration();
ui->graphicsTab->SetConfiguration();
ui->audioTab->SetConfiguration();
ui->debugTab->SetConfiguration();
ui->webTab->SetConfiguration();
}
void ConfigureDialog::ApplyConfiguration() {
ui->generalTab->ApplyConfiguration();
ui->gameListTab->ApplyConfiguration();
ui->uiTab->ApplyConfiguration();
ui->systemTab->ApplyConfiguration();
ui->profileManagerTab->ApplyConfiguration();
ui->inputTab->ApplyConfiguration();
@@ -47,11 +56,18 @@ void ConfigureDialog::ApplyConfiguration() {
}
void ConfigureDialog::PopulateSelectionList() {
ui->selectorList->clear();
const std::array<std::pair<QString, QStringList>, 4> items{
{{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}},
{tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}},
{tr("Graphics"), {tr("Graphics")}},
{tr("Controls"), {tr("Input"), tr("Hotkeys")}}}};
{{tr("General"),
{QT_TR_NOOP(QStringLiteral("General")), QT_TR_NOOP(QStringLiteral("Web")),
QT_TR_NOOP(QStringLiteral("Debug")), QT_TR_NOOP(QStringLiteral("UI"))}},
{tr("System"),
{QT_TR_NOOP(QStringLiteral("System")), QT_TR_NOOP(QStringLiteral("Profiles")),
QT_TR_NOOP(QStringLiteral("Audio"))}},
{tr("Graphics"), {QT_TR_NOOP(QStringLiteral("Graphics"))}},
{tr("Controls"),
{QT_TR_NOOP(QStringLiteral("Input")), QT_TR_NOOP(QStringLiteral("Hotkeys"))}}}};
for (const auto& entry : items) {
auto* const item = new QListWidgetItem(entry.first);
@@ -66,21 +82,49 @@ void ConfigureDialog::UpdateVisibleTabs() {
if (items.isEmpty())
return;
const std::map<QString, QWidget*> widgets = {{tr("General"), ui->generalTab},
{tr("System"), ui->systemTab},
{tr("Profiles"), ui->profileManagerTab},
{tr("Input"), ui->inputTab},
{tr("Hotkeys"), ui->hotkeysTab},
{tr("Graphics"), ui->graphicsTab},
{tr("Audio"), ui->audioTab},
{tr("Debug"), ui->debugTab},
{tr("Web"), ui->webTab},
{tr("Game List"), ui->gameListTab}};
const std::map<QString, QWidget*> widgets = {
{QStringLiteral("General"), ui->generalTab},
{QStringLiteral("System"), ui->systemTab},
{QStringLiteral("Profiles"), ui->profileManagerTab},
{QStringLiteral("Input"), ui->inputTab},
{QStringLiteral("Hotkeys"), ui->hotkeysTab},
{QStringLiteral("Graphics"), ui->graphicsTab},
{QStringLiteral("Audio"), ui->audioTab},
{QStringLiteral("Debug"), ui->debugTab},
{QStringLiteral("Web"), ui->webTab},
{QStringLiteral("UI"), ui->uiTab}};
ui->tabWidget->clear();
const QStringList tabs = items[0]->data(Qt::UserRole).toStringList();
for (const auto& tab : tabs)
ui->tabWidget->addTab(widgets.find(tab)->second, tab);
ui->tabWidget->addTab(widgets.find(tab)->second, tr(qPrintable(tab)));
}
void ConfigureDialog::onLanguageChanged(const QString& locale) {
emit languageChanged(locale);
// first apply the configuration, and then restore the display
ApplyConfiguration();
RetranslateUI();
SetConfiguration();
}
void ConfigureDialog::RetranslateUI() {
int old_row = ui->selectorList->currentRow();
int old_index = ui->tabWidget->currentIndex();
ui->retranslateUi(this);
PopulateSelectionList();
// restore selection after repopulating
ui->selectorList->setCurrentRow(old_row);
ui->tabWidget->setCurrentIndex(old_index);
ui->generalTab->RetranslateUI();
ui->uiTab->RetranslateUI();
ui->systemTab->RetranslateUI();
ui->inputTab->RetranslateUI();
ui->graphicsTab->RetranslateUI();
ui->audioTab->RetranslateUI();
ui->debugTab->RetranslateUI();
ui->webTab->RetranslateUI();
}

View File

@@ -22,10 +22,17 @@ public:
void ApplyConfiguration();
private slots:
void onLanguageChanged(const QString& locale);
signals:
void languageChanged(const QString& locale);
private:
void SetConfiguration();
void UpdateVisibleTabs();
void PopulateSelectionList();
void RetranslateUI();
std::unique_ptr<Ui::ConfigureDialog> ui;
HotkeyRegistry& registry;

View File

@@ -13,13 +13,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ui->setupUi(this);
for (const auto& theme : UISettings::themes) {
ui->theme_combobox->addItem(QString::fromUtf8(theme.first),
QString::fromUtf8(theme.second));
}
SetConfiguration();
connect(ui->toggle_deepscan, &QCheckBox::stateChanged, this,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); });
@@ -32,7 +25,6 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_deepscan->setChecked(UISettings::values.game_directory_deepscan);
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
}
@@ -40,8 +32,10 @@ void ConfigureGeneral::ApplyConfiguration() {
UISettings::values.game_directory_deepscan = ui->toggle_deepscan->isChecked();
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
UISettings::values.theme =
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
}
void ConfigureGeneral::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -21,9 +21,9 @@ public:
~ConfigureGeneral() override;
void ApplyConfiguration();
private:
void RetranslateUI();
void SetConfiguration();
private:
std::unique_ptr<Ui::ConfigureGeneral> ui;
};

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>407</height>
<width>345</width>
<height>493</height>
</rect>
</property>
<property name="windowTitle">
@@ -70,33 +70,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="theme_group_box">
<property name="title">
<string>Theme</string>
</property>
<layout class="QHBoxLayout" name="theme_qhbox_layout">
<item>
<layout class="QVBoxLayout" name="theme_qvbox_layout">
<item>
<layout class="QHBoxLayout" name="theme_qhbox_layout_2">
<item>
<widget class="QLabel" name="theme_label">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="theme_combobox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@@ -110,3 +110,7 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) {
const QIcon color_icon(pixmap);
ui->bg_button->setIcon(color_icon);
}
void ConfigureGraphics::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -19,8 +19,7 @@ public:
~ConfigureGraphics() override;
void ApplyConfiguration();
private:
void RetranslateUI();
void SetConfiguration();
void UpdateBackgroundColorButton(QColor color);

View File

@@ -209,3 +209,7 @@ void ConfigureInput::RestoreDefaults() {
ui->touchscreen_enabled->setCheckState(Qt::Checked);
UpdateUIEnabled();
}
void ConfigureInput::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -31,6 +31,7 @@ public:
/// Save all button configurations to settings file
void ApplyConfiguration();
void RetranslateUI();
private:
void UpdateUIEnabled();

View File

@@ -137,3 +137,7 @@ void ConfigureInputSimple::OnSelectProfile(int index) {
void ConfigureInputSimple::OnConfigure() {
std::get<2>(INPUT_PROFILES.at(ui->profile_combobox->currentIndex()))(this);
}
void ConfigureInputSimple::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -28,11 +28,11 @@ public:
/// Save all button configurations to settings file
void ApplyConfiguration();
private:
void RetranslateUI();
/// Load configuration settings.
void LoadConfiguration();
private:
void OnSelectProfile(int index);
void OnConfigure();

View File

@@ -102,3 +102,7 @@ void ConfigureSystem::RefreshConsoleID() {
ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
}
void ConfigureSystem::RetranslateUI() {
ui->retranslateUi(this);
}

View File

@@ -21,10 +21,10 @@ public:
~ConfigureSystem() override;
void ApplyConfiguration();
void SetConfiguration();
void RetranslateUI();
private:
void SetConfiguration();
void ReadSystemSettings();
void RefreshConsoleID();

View File

@@ -5,10 +5,12 @@
#include <array>
#include <utility>
#include <QDirIterator>
#include "common/common_types.h"
#include "core/settings.h"
#include "ui_configure_gamelist.h"
#include "yuzu/configuration/configure_gamelist.h"
#include "ui_configure_ui.h"
#include "yuzu/configuration/configure_ui.h"
#include "yuzu/ui_settings.h"
namespace {
@@ -28,29 +30,36 @@ constexpr std::array row_text_names{
};
} // Anonymous namespace
ConfigureGameList::ConfigureGameList(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGameList) {
ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) {
ui->setupUi(this);
InitializeLanguageComboBox();
for (const auto& theme : UISettings::themes) {
ui->theme_combobox->addItem(QString::fromStdString(theme.first),
QString::fromStdString(theme.second));
}
InitializeIconSizeComboBox();
InitializeRowComboBoxes();
SetConfiguration();
// Force game list reload if any of the relevant settings are changed.
connect(ui->show_unknown, &QCheckBox::stateChanged, this,
&ConfigureGameList::RequestGameListUpdate);
connect(ui->show_unknown, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureGameList::RequestGameListUpdate);
&ConfigureUi::RequestGameListUpdate);
connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureGameList::RequestGameListUpdate);
&ConfigureUi::RequestGameListUpdate);
connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureGameList::RequestGameListUpdate);
&ConfigureUi::RequestGameListUpdate);
}
ConfigureGameList::~ConfigureGameList() = default;
ConfigureUi::~ConfigureUi() = default;
void ConfigureGameList::ApplyConfiguration() {
void ConfigureUi::ApplyConfiguration() {
UISettings::values.theme =
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
UISettings::values.show_unknown = ui->show_unknown->isChecked();
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
@@ -59,11 +68,14 @@ void ConfigureGameList::ApplyConfiguration() {
Settings::Apply();
}
void ConfigureGameList::RequestGameListUpdate() {
void ConfigureUi::RequestGameListUpdate() {
UISettings::values.is_game_list_reload_pending.exchange(true);
}
void ConfigureGameList::SetConfiguration() {
void ConfigureUi::SetConfiguration() {
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
ui->language_combobox->setCurrentIndex(
ui->language_combobox->findData(UISettings::values.language));
ui->show_unknown->setChecked(UISettings::values.show_unknown);
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
ui->icon_size_combobox->setCurrentIndex(
@@ -74,7 +86,7 @@ void ConfigureGameList::SetConfiguration() {
ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id));
}
void ConfigureGameList::changeEvent(QEvent* event) {
void ConfigureUi::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
return;
@@ -83,7 +95,7 @@ void ConfigureGameList::changeEvent(QEvent* event) {
QWidget::changeEvent(event);
}
void ConfigureGameList::RetranslateUI() {
void ConfigureUi::RetranslateUI() {
ui->retranslateUi(this);
for (int i = 0; i < ui->icon_size_combobox->count(); i++) {
@@ -98,13 +110,32 @@ void ConfigureGameList::RetranslateUI() {
}
}
void ConfigureGameList::InitializeIconSizeComboBox() {
void ConfigureUi::InitializeLanguageComboBox() {
ui->language_combobox->addItem(tr("<System>"), QString());
ui->language_combobox->addItem(tr("English"), QStringLiteral("en"));
QDirIterator it(QStringLiteral(":/languages"), QDirIterator::NoIteratorFlags);
while (it.hasNext()) {
QString locale = it.next();
locale.truncate(locale.lastIndexOf(QLatin1Char('.')));
locale.remove(0, locale.lastIndexOf(QLatin1Char('/')) + 1);
const QString lang = QLocale::languageToString(QLocale(locale).language());
ui->language_combobox->addItem(lang, locale);
}
// Unlike other configuration changes, interface language changes need to be reflected on the
// interface immediately. This is done by passing a signal to the main window, and then
// retranslating when passing back.
connect(ui->language_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureUi::onLanguageChanged);
}
void ConfigureUi::InitializeIconSizeComboBox() {
for (const auto& size : default_icon_sizes) {
ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first);
}
}
void ConfigureGameList::InitializeRowComboBoxes() {
void ConfigureUi::InitializeRowComboBoxes() {
for (std::size_t i = 0; i < row_text_names.size(); ++i) {
const QString row_text_name = QString::fromUtf8(row_text_names[i]);
@@ -112,3 +143,10 @@ void ConfigureGameList::InitializeRowComboBoxes() {
ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}
}
void ConfigureUi::onLanguageChanged(int index) {
if (index == -1)
return;
emit languageChanged(ui->language_combobox->itemData(index).toString());
}

View File

@@ -8,28 +8,34 @@
#include <QWidget>
namespace Ui {
class ConfigureGameList;
class ConfigureUi;
}
class ConfigureGameList : public QWidget {
class ConfigureUi : public QWidget {
Q_OBJECT
public:
explicit ConfigureGameList(QWidget* parent = nullptr);
~ConfigureGameList() override;
explicit ConfigureUi(QWidget* parent = nullptr);
~ConfigureUi() override;
void ApplyConfiguration();
void RetranslateUI();
void SetConfiguration();
private slots:
void onLanguageChanged(int index);
signals:
void languageChanged(const QString& locale);
private:
void RequestGameListUpdate();
void SetConfiguration();
void changeEvent(QEvent*) override;
void RetranslateUI();
void InitializeLanguageComboBox();
void InitializeIconSizeComboBox();
void InitializeRowComboBoxes();
std::unique_ptr<Ui::ConfigureGameList> ui;
std::unique_ptr<Ui::ConfigureUi> ui;
};

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureGameList</class>
<widget class="QWidget" name="ConfigureGameList">
<class>ConfigureUi</class>
<widget class="QWidget" name="ConfigureUi">
<property name="geometry">
<rect>
<x>0</x>
@@ -21,7 +21,64 @@
<property name="title">
<string>General</string>
</property>
<layout class="QHBoxLayout" name="GeneralHorizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_change_language_info">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Note: Changing language will apply your configuration.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="language_label">
<property name="text">
<string>Interface language:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="language_combobox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="theme_label">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="theme_combobox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="GameListGroupBox">
<property name="title">
<string>Game List</string>
</property>
<layout class="QHBoxLayout" name="GameListHorizontalLayout">
<item>
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
<item>
@@ -38,19 +95,6 @@
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="IconSizeGroupBox">
<property name="title">
<string>Icon Size</string>
</property>
<layout class="QHBoxLayout" name="icon_size_qhbox_layout">
<item>
<layout class="QVBoxLayout" name="icon_size_qvbox_layout">
<item>
<layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
<item>
@@ -65,19 +109,6 @@
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="RowGroupBox">
<property name="title">
<string>Row Text</string>
</property>
<layout class="QHBoxLayout" name="RowHorizontalLayout">
<item>
<layout class="QVBoxLayout" name="RowVerticalLayout">
<item>
<layout class="QHBoxLayout" name="row_1_qhbox_layout">
<item>

View File

@@ -21,6 +21,7 @@ public:
void ApplyConfiguration();
void RetranslateUI();
void SetConfiguration();
private:
void RefreshTelemetryID();
@@ -28,8 +29,6 @@ private:
void VerifyLogin();
void OnLoginVerified();
void SetConfiguration();
bool user_verified = true;
QFutureWatcher<bool> verify_watcher;

View File

@@ -176,6 +176,8 @@ GMainWindow::GMainWindow()
provider(std::make_unique<FileSys::ManualContentProvider>()) {
InitializeLogging();
LoadTranslation();
debug_context = Tegra::DebugContext::Construct();
setAcceptDrops(true);
@@ -884,6 +886,9 @@ bool GMainWindow::LoadROM(const QString& filename) {
}
game_path = filename;
std::string title;
system.GetAppLoader().ReadTitle(title);
game_title = QString::fromStdString(title);
system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "Qt");
return true;
}
@@ -948,7 +953,7 @@ void GMainWindow::BootGame(const QString& filename) {
title_name = FileUtil::GetFilename(filename.toStdString());
}
UpdateWindowTitle(QString::fromStdString(title_name));
UpdateWindowTitle();
loading_screen->Prepare(Core::System::GetInstance().GetAppLoader());
loading_screen->show();
@@ -990,6 +995,7 @@ void GMainWindow::ShutdownGame() {
game_list->show();
game_list->setFilterFocus();
game_title.clear();
UpdateWindowTitle();
// Disable status bar updates
@@ -1687,6 +1693,8 @@ void GMainWindow::OnConfigure() {
const bool old_discord_presence = UISettings::values.enable_discord_presence;
ConfigureDialog configure_dialog(this, hotkey_registry);
connect(&configure_dialog, &ConfigureDialog::languageChanged, this,
&GMainWindow::OnLanguageChanged);
const auto result = configure_dialog.exec();
if (result != QDialog::Accepted) {
return;
@@ -1786,16 +1794,16 @@ void GMainWindow::OnCaptureScreenshot() {
OnStartGame();
}
void GMainWindow::UpdateWindowTitle(const QString& title_name) {
void GMainWindow::UpdateWindowTitle() {
const QString full_name = QString::fromUtf8(Common::g_build_fullname);
const QString branch_name = QString::fromUtf8(Common::g_scm_branch);
const QString description = QString::fromUtf8(Common::g_scm_desc);
if (title_name.isEmpty()) {
setWindowTitle(QStringLiteral("yuzu %1| %2-%3").arg(full_name, branch_name, description));
if (game_title.isEmpty()) {
setWindowTitle(tr("yuzu %1| %2-%3").arg(full_name, branch_name, description));
} else {
setWindowTitle(QStringLiteral("yuzu %1| %4 | %2-%3")
.arg(full_name, branch_name, description, title_name));
setWindowTitle(
tr("yuzu %1| %4 | %2-%3").arg(full_name, branch_name, description, game_title));
}
}
@@ -2136,6 +2144,41 @@ void GMainWindow::UpdateUITheme() {
emit UpdateThemedIcons();
}
void GMainWindow::LoadTranslation() {
// If the selected language is English, no need to install any translation
if (UISettings::values.language == QStringLiteral("en")) {
return;
}
bool loaded;
if (UISettings::values.language.isEmpty()) {
// If the selected language is empty, use system locale
loaded = translator.load(QLocale(), QStringLiteral(""), QStringLiteral(""),
QStringLiteral(":/languages/"));
} else {
// Otherwise load from the specified file
loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/"));
}
if (loaded) {
qApp->installTranslator(&translator);
} else {
UISettings::values.language = QStringLiteral("en");
}
}
void GMainWindow::OnLanguageChanged(const QString& locale) {
if (UISettings::values.language != QStringLiteral("en")) {
qApp->removeTranslator(&translator);
}
UISettings::values.language = locale;
LoadTranslation();
ui.retranslateUi(this);
UpdateWindowTitle();
}
void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
#ifdef USE_DISCORD_PRESENCE
if (state) {

View File

@@ -10,6 +10,7 @@
#include <QMainWindow>
#include <QTimer>
#include <QTranslator>
#include "common/common_types.h"
#include "core/core.h"
@@ -206,11 +207,13 @@ private slots:
void OnCaptureScreenshot();
void OnCoreError(Core::System::ResultStatus, std::string);
void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
void OnLanguageChanged(const QString& locale);
private:
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
void UpdateWindowTitle(const QString& title_name = {});
void UpdateWindowTitle();
void UpdateStatusBar();
void LoadTranslation();
Ui::MainWindow ui;
@@ -232,6 +235,8 @@ private:
// Whether emulation is currently running in yuzu.
bool emulation_running = false;
std::unique_ptr<EmuThread> emu_thread;
// The title of the game currently running
QString game_title;
// The path to the game currently running
QString game_path;
@@ -252,6 +257,8 @@ private:
HotkeyRegistry hotkey_registry;
QTranslator translator;
protected:
void dropEvent(QDropEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;

View File

@@ -58,6 +58,7 @@ struct Values {
QString game_directory_path;
bool game_directory_deepscan;
QStringList recent_files;
QString language;
QString theme;