Further improves localization (#191). Allows switching and setting the chosen localization properly.

This commit is contained in:
Felix (xq) Queißner 2021-03-17 11:54:43 +01:00
parent a2f36ec4d1
commit 10684b6d82
17 changed files with 250 additions and 79 deletions

View File

@ -64,6 +64,12 @@ BrowserTab::BrowserTab(MainWindow *mainWindow) : QWidget(nullptr),
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->setUiDensity(kristall::globals().options.ui_density);
addProtocolHandler<GeminiClient>();

View File

@ -43,7 +43,8 @@
<string>Back</string>
</property>
<property name="icon">
<iconset theme="go-previous"/>
<iconset theme="go-previous">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -59,7 +60,8 @@
<string>Forward</string>
</property>
<property name="icon">
<iconset theme="go-next"/>
<iconset theme="go-next">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -75,7 +77,8 @@
<string>Stop</string>
</property>
<property name="icon">
<iconset theme="process-stop"/>
<iconset theme="process-stop">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -91,7 +94,8 @@
<string>Reload</string>
</property>
<property name="icon">
<iconset theme="view-refresh"/>
<iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -107,7 +111,8 @@
<string>Home</string>
</property>
<property name="icon">
<iconset theme="go-home"/>
<iconset theme="go-home">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -123,7 +128,8 @@
<string>/</string>
</property>
<property name="icon">
<iconset theme="go-top"/>
<iconset theme="go-top">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -139,7 +145,8 @@
<string>P</string>
</property>
<property name="icon">
<iconset theme="go-up"/>
<iconset theme="go-up">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -211,11 +218,11 @@
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
<string notr="true" extracomment="Must not be translated, otherwise the content will be replaced when switching languages">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Start surfin!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openLinks">
<bool>false</bool>
@ -267,7 +274,8 @@ p, li { white-space: pre-wrap; }
<string>Previous</string>
</property>
<property name="icon">
<iconset theme="go-up-search"/>
<iconset theme="go-up-search">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -280,7 +288,8 @@ p, li { white-space: pre-wrap; }
<string>Next</string>
</property>
<property name="icon">
<iconset theme="go-down-search"/>
<iconset theme="go-down-search">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -293,7 +302,8 @@ p, li { white-space: pre-wrap; }
<string>Hide</string>
</property>
<property name="icon">
<iconset theme="window-close"/>
<iconset theme="window-close">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>

View File

@ -1,5 +1,6 @@
#include "certificateiodialog.hpp"
#include "ui_certificateiodialog.h"
#include "kristall.hpp"
#include <QFileDialog>
#include <QPushButton>
@ -11,6 +12,12 @@ CertificateIoDialog::CertificateIoDialog(QWidget *parent) :
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->ui->key_type->clear();
this->ui->key_type->addItem("RSA", QVariant::fromValue<int>(QSsl::Rsa));
this->ui->key_type->addItem("ECDSA", QVariant::fromValue<int>(QSsl::Ec));

View File

@ -17,6 +17,12 @@ CertificateManagementDialog::CertificateManagementDialog(QWidget *parent) :
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->ui->certificates->setModel(&identity_set);
this->ui->certificates->expandAll();

View File

@ -14,6 +14,13 @@ CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent) :
ui(new Ui::CertificateSelectionDialog)
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->ui->server_request->setVisible(false);
this->ui->certificates->setModel(&kristall::globals().identities);

View File

@ -13,6 +13,12 @@ NewIdentitiyDialog::NewIdentitiyDialog(QWidget *parent) :
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
ui->display_name->setText("Unnamed");
ui->common_name->setText("Unnamed");
ui->expiration_date->setDate(QDate::currentDate().addYears(1));

View File

@ -21,6 +21,12 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
static_assert(DocumentStyle::Fixed == 0);
static_assert(DocumentStyle::AutoDarkTheme == 1);
static_assert(DocumentStyle::AutoLightTheme == 2);
@ -103,6 +109,11 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
this->ui->style_scroll_layout->minimumSize().width()
+ this->ui->style_scroll_area->verticalScrollBar()->sizeHint().width());
});
this->ui->selected_language->clear();
this->ui->selected_language->addItem(QIcon(), tr("System language"), QString(""));
this->ui->selected_language->addItem(QIcon(":/icons/languages/en.svg"), QLocale("en").nativeLanguageName(), QString("en"));
this->ui->selected_language->addItem(QIcon(":/icons/languages/ru.svg"), QLocale("ru").nativeLanguageName(), QString("ru"));
}
SettingsDialog::~SettingsDialog()
@ -387,6 +398,32 @@ void SettingsDialog::setOptions(const GenericSettings &options)
}
}
std::optional<QLocale> SettingsDialog::locale() const
{
QString locale_str = this->ui->selected_language->currentData().toString();
if(locale_str.isEmpty())
return std::nullopt;
else
return QLocale(locale_str);
}
void SettingsDialog::setLocale(std::optional<QLocale> locale)
{
if(locale == std::nullopt)
{
this->ui->selected_language->setCurrentIndex(0);
}
else
{
switch(locale->language())
{
default: this->ui->selected_language->setCurrentIndex(0); break;
case QLocale::English: this->ui->selected_language->setCurrentIndex(1); break;
case QLocale::Russian: this->ui->selected_language->setCurrentIndex(2); break;
}
}
}
GenericSettings SettingsDialog::options() const
{
return this->current_options;
@ -988,3 +1025,10 @@ void SettingsDialog::on_session_restore_behaviour_currentIndexChanged(int index)
{
this->current_options.session_restore_behaviour = GenericSettings::SessionRestoreBehaviour(this->ui->session_restore_behaviour->itemData(index).toInt());
}
void SettingsDialog::on_selected_language_currentIndexChanged(int index)
{
auto const language_id = this->ui->selected_language->itemData(index, Qt::UserRole).toString();
kristall::globals().localization->translate(QLocale(language_id));
}

View File

@ -2,6 +2,7 @@
#define SETTINGSDIALOG_HPP
#include <QDialog>
#include <optional>
#include "renderers/geminirenderer.hpp"
#include "protocolsetup.hpp"
@ -39,6 +40,9 @@ public:
GenericSettings options() const;
void setOptions(GenericSettings const & options);
std::optional<QLocale> locale() const;
void setLocale(std::optional<QLocale> locale);
private slots:
void on_std_change_font_clicked();
@ -178,6 +182,8 @@ private slots:
void on_session_restore_behaviour_currentIndexChanged(int index);
void on_selected_language_currentIndexChanged(int index);
private:
void reloadStylePreview();

View File

@ -32,42 +32,42 @@
<string>Generic</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Start Page:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QLineEdit" name="start_page">
<property name="placeholderText">
<string>about://blank</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_40">
<property name="text">
<string>Search engine:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="search_engine">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Additional toolbar buttons</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_99">
<item>
<widget class="QCheckBox" name="enable_home_btn">
@ -99,54 +99,54 @@
</item>
</layout>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Startup Behaviour</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QComboBox" name="session_restore_behaviour"/>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>UI Theme</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QComboBox" name="ui_theme"/>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_34">
<property name="text">
<string>Icon Theme</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QComboBox" name="icon_theme"/>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>UI Density</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QComboBox" name="ui_density"/>
</item>
<item row="7" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Enabled Protocols</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="enable_gemini">
@ -191,14 +191,14 @@
</item>
</layout>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Unknown Scheme</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QRadioButton" name="scheme_os_default">
@ -222,38 +222,38 @@
</item>
</layout>
</item>
<item row="9" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Max. Number of Redirections</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="10" column="1">
<widget class="QSpinBox" name="max_redirects">
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Redirection Handling</string>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="11" column="1">
<widget class="QComboBox" name="redirection_mode"/>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>Network Timeout</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QSpinBox" name="network_timeout">
<property name="suffix">
<string> ms</string>
@ -266,6 +266,16 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_44">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="selected_language"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="display_tab">
@ -1651,14 +1661,14 @@
</connection>
</connections>
<buttongroups>
<buttongroup name="buttonGroup_3"/>
<buttongroup name="buttonGroup"/>
<buttongroup name="buttonGroup_5"/>
<buttongroup name="buttonGroup_4"/>
<buttongroup name="buttonGroup_7"/>
<buttongroup name="buttonGroup_6"/>
<buttongroup name="buttonGroup_5"/>
<buttongroup name="buttonGroup"/>
<buttongroup name="buttonGroup_9"/>
<buttongroup name="buttonGroup_8"/>
<buttongroup name="buttonGroup_3"/>
<buttongroup name="buttonGroup_4"/>
<buttongroup name="buttonGroup_2"/>
<buttongroup name="buttonGroup_8"/>
<buttongroup name="buttonGroup_9"/>
</buttongroups>
</ui>

View File

@ -5,8 +5,6 @@
#include <QSettings>
#include <QClipboard>
#include <QSslCertificate>
#include <QTranslator>
#include <QLocale>
#include "identitycollection.hpp"
#include "ssltrust.hpp"
@ -14,6 +12,7 @@
#include "protocolsetup.hpp"
#include "documentstyle.hpp"
#include "cachehandler.hpp"
#include "localization.hpp"
enum class Theme : int
{
@ -166,13 +165,6 @@ namespace kristall
QDir styles;
};
struct Localization
{
QLocale locale;
QTranslator qt;
QTranslator kristall;
};
struct Globals
{
ProtocolSetup protocols;
@ -191,7 +183,7 @@ namespace kristall
Dirs dirs;
Localization localization;
std::unique_ptr<Localization> localization;
};
//! returns the instance of the globals structure
@ -233,9 +225,6 @@ namespace kristall
//! Saves the current session including all windows, tabs and positions.
void saveSession();
//! Changes the currently used locale
void setLocale(QLocale const & locale);
//! Saves the currently used locale
void saveLocale();
}

View File

@ -105,6 +105,7 @@ SOURCES += \
favouritecollection.cpp \
identitycollection.cpp \
ioutil.cpp \
localization.cpp \
main.cpp \
mainwindow.cpp \
renderers/htmlrenderer.cpp \
@ -155,6 +156,7 @@ HEADERS += \
identitycollection.hpp \
ioutil.hpp \
kristall.hpp \
localization.hpp \
mainwindow.hpp \
renderers/htmlrenderer.hpp \
renderers/markdownrenderer.hpp \

31
src/localization.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "kristall.hpp"
#include <QDebug>
#include <QLibraryInfo>
#include "localization.hpp"
Localization::Localization(QObject *parent) : QObject(parent)
{
}
void Localization::setLocale(const std::optional<QLocale> &locale)
{
this->locale = locale;
if(this->locale != std::nullopt)
this->translate(*this->locale);
else
this->translate(QLocale());
}
void Localization::translate(const QLocale &locale)
{
this->qt.load(locale, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath));
this->kristall.load(locale, "kristall", "_", ":/i18n");
emit this->translationChanged();
qDebug() << "new locale is" << locale.bcp47Name() << locale.nativeLanguageName();
}

28
src/localization.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef LOCALIZATION_HPP
#define LOCALIZATION_HPP
#include <QObject>
#include <QTranslator>
#include <QLocale>
#include <optional>
class Localization : public QObject
{
Q_OBJECT
public:
explicit Localization(QObject *parent = nullptr);
void setLocale(std::optional<QLocale> const & locale);
void translate(QLocale const & locale);
signals:
void translationChanged();
public:
std::optional<QLocale> locale;
QTranslator qt;
QTranslator kristall;
};
#endif // LOCALIZATION_HPP

View File

@ -375,22 +375,15 @@ MainWindow * kristall::openNewWindow(QVector<NamedUrl> const & urls)
return window;
}
//! Changes the currently used locale
void kristall::setLocale(QLocale const & locale)
{
auto & i18n = kristall::globals().localization;
i18n.locale = locale;
i18n.qt.load(i18n.locale, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath));
i18n.kristall.load(i18n.locale, "kristall", "_", ":/i18n");
}
//! Saves the currently used locale
void kristall::saveLocale()
{
if(app_settings_ptr == nullptr)
return;
app_settings_ptr->setValue("language", kristall::globals().localization.locale.bcp47Name());
if(auto const locale = kristall::globals().localization->locale; locale != std::nullopt)
app_settings_ptr->setValue("language", locale->bcp47Name());
else
app_settings_ptr->setValue("language", QString(""));
app_settings_ptr->sync();
}
@ -450,20 +443,19 @@ int main(int argc, char *argv[])
// Initialize localization
{
// Load the currently selected locale
auto const lang_id = app_settings.value("language", QString()).toString();
if(not lang_id.isEmpty()) {
kristall::setLocale( QLocale(lang_id) );
}
else {
kristall::setLocale ( QLocale() );
}
auto & i18n = kristall::globals().localization;
app.installTranslator(&i18n.qt);
app.installTranslator(&i18n.kristall);
qDebug() << "current locale" << i18n.locale.nativeLanguageName();
i18n = std::make_unique<Localization>();
auto const locale_id = app_settings.value("language", QString("")).toString();
if(not locale_id.isEmpty())
i18n->setLocale(QLocale(locale_id));
else
i18n->setLocale(std::nullopt);
qApp->installTranslator(&i18n->qt);
qApp->installTranslator(&i18n->kristall);
}
addEmojiSubstitutions();

View File

@ -33,6 +33,12 @@ MainWindow::MainWindow(QApplication * app, QWidget *parent) :
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->url_status->setElideMode(Qt::ElideMiddle);
this->statusBar()->addWidget(this->url_status);
@ -469,13 +475,17 @@ void MainWindow::on_actionSettings_triggered()
dialog.setOptions(kristall::globals().options);
dialog.setGeminiSslTrust(kristall::globals().trust.gemini);
dialog.setHttpsSslTrust(kristall::globals().trust.https);
dialog.setLocale(kristall::globals().localization->locale);
if(dialog.exec() != QDialog::Accepted) {
kristall::setTheme(kristall::globals().options.theme);
kristall::globals().localization->setLocale(kristall::globals().localization->locale);
this->setUiDensity(kristall::globals().options.ui_density, false);
return;
}
kristall::globals().localization->setLocale(dialog.locale());
kristall::globals().trust.gemini = dialog.geminiSslTrust();
kristall::globals().trust.https = dialog.httpsSslTrust();
kristall::globals().options = dialog.options();
@ -483,6 +493,7 @@ void MainWindow::on_actionSettings_triggered()
kristall::globals().protocols = dialog.protocols();
kristall::globals().document_style = dialog.geminiStyle();
kristall::saveLocale();
kristall::applySettings();
kristall::saveSettings();

View File

@ -1,6 +1,8 @@
#include "mediaplayer.hpp"
#include "ui_mediaplayer.h"
#include "kristall.hpp"
#include <QMediaContent>
#include <QToolButton>
#include <QTime>
@ -14,6 +16,12 @@ MediaPlayer::MediaPlayer(QWidget *parent) :
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->player.setVideoOutput(this->ui->video_out);
connect(&this->player, &QMediaPlayer::durationChanged, this->ui->media_progress, &QSlider::setMaximum);

View File

@ -1,12 +1,20 @@
#include "ssltrusteditor.hpp"
#include "ui_ssltrusteditor.h"
#include "kristall.hpp"
SslTrustEditor::SslTrustEditor(QWidget *parent) :
QWidget(parent),
ui(new Ui::SslTrustEditor)
{
ui->setupUi(this);
connect( // connect with "this" as context, so the connection will die when the window is destroyed
kristall::globals().localization.get(), &Localization::translationChanged,
this, [this]() { this->ui->retranslateUi(this); },
Qt::DirectConnection
);
this->ui->trust_level->clear();
this->ui->trust_level->addItem(tr("Trust on first encounter"), QVariant::fromValue<int>(SslTrust::TrustOnFirstUse));
this->ui->trust_level->addItem(tr("Trust everything"), QVariant::fromValue<int>(SslTrust::TrustEverything));