Unify the way to generate the language list in WebUI and GUI

PR #17994.
This commit is contained in:
brvphoenix 2022-12-25 21:44:37 +08:00 committed by GitHub
parent c5a4a0db2c
commit b33dc7d831
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 133 additions and 154 deletions

View file

@ -53,6 +53,8 @@
#include <zlib.h> #include <zlib.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug>
#include <QLocale>
#include <QMimeDatabase> #include <QMimeDatabase>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSet> #include <QSet>
@ -403,6 +405,94 @@ QString Utils::Misc::getUserIDString()
return uid; return uid;
} }
QString Utils::Misc::languageToLocalizedString(const QString &localeStr)
{
if (localeStr.startsWith(u"eo", Qt::CaseInsensitive))
{
// QLocale doesn't work with that locale. Esperanto isn't a "real" language.
return C_LOCALE_ESPERANTO;
}
if (localeStr.startsWith(u"ltg", Qt::CaseInsensitive))
{
// QLocale doesn't work with that locale.
return C_LOCALE_LATGALIAN;
}
const QLocale locale {localeStr};
switch (locale.language())
{
case QLocale::Arabic: return C_LOCALE_ARABIC;
case QLocale::Armenian: return C_LOCALE_ARMENIAN;
case QLocale::Azerbaijani: return C_LOCALE_AZERBAIJANI;
case QLocale::Basque: return C_LOCALE_BASQUE;
case QLocale::Bulgarian: return C_LOCALE_BULGARIAN;
case QLocale::Byelorussian: return C_LOCALE_BYELORUSSIAN;
case QLocale::Catalan: return C_LOCALE_CATALAN;
case QLocale::Chinese:
switch (locale.country())
{
case QLocale::China: return C_LOCALE_CHINESE_SIMPLIFIED;
case QLocale::HongKong: return C_LOCALE_CHINESE_TRADITIONAL_HK;
default: return C_LOCALE_CHINESE_TRADITIONAL_TW;
}
case QLocale::Croatian: return C_LOCALE_CROATIAN;
case QLocale::Czech: return C_LOCALE_CZECH;
case QLocale::Danish: return C_LOCALE_DANISH;
case QLocale::Dutch: return C_LOCALE_DUTCH;
case QLocale::English:
switch (locale.country())
{
case QLocale::Australia: return C_LOCALE_ENGLISH_AUSTRALIA;
case QLocale::UnitedKingdom: return C_LOCALE_ENGLISH_UNITEDKINGDOM;
default: return C_LOCALE_ENGLISH;
}
case QLocale::Estonian: return C_LOCALE_ESTONIAN;
case QLocale::Finnish: return C_LOCALE_FINNISH;
case QLocale::French: return C_LOCALE_FRENCH;
case QLocale::Galician: return C_LOCALE_GALICIAN;
case QLocale::Georgian: return C_LOCALE_GEORGIAN;
case QLocale::German: return C_LOCALE_GERMAN;
case QLocale::Greek: return C_LOCALE_GREEK;
case QLocale::Hebrew: return C_LOCALE_HEBREW;
case QLocale::Hindi: return C_LOCALE_HINDI;
case QLocale::Hungarian: return C_LOCALE_HUNGARIAN;
case QLocale::Icelandic: return C_LOCALE_ICELANDIC;
case QLocale::Indonesian: return C_LOCALE_INDONESIAN;
case QLocale::Italian: return C_LOCALE_ITALIAN;
case QLocale::Japanese: return C_LOCALE_JAPANESE;
case QLocale::Korean: return C_LOCALE_KOREAN;
case QLocale::Latvian: return C_LOCALE_LATVIAN;
case QLocale::Lithuanian: return C_LOCALE_LITHUANIAN;
case QLocale::Malay: return C_LOCALE_MALAY;
case QLocale::Mongolian: return C_LOCALE_MONGOLIAN;
case QLocale::NorwegianBokmal: return C_LOCALE_NORWEGIAN;
case QLocale::Occitan: return C_LOCALE_OCCITAN;
case QLocale::Persian: return C_LOCALE_PERSIAN;
case QLocale::Polish: return C_LOCALE_POLISH;
case QLocale::Portuguese:
if (locale.country() == QLocale::Brazil)
return C_LOCALE_PORTUGUESE_BRAZIL;
return C_LOCALE_PORTUGUESE;
case QLocale::Romanian: return C_LOCALE_ROMANIAN;
case QLocale::Russian: return C_LOCALE_RUSSIAN;
case QLocale::Serbian: return C_LOCALE_SERBIAN;
case QLocale::Slovak: return C_LOCALE_SLOVAK;
case QLocale::Slovenian: return C_LOCALE_SLOVENIAN;
case QLocale::Spanish: return C_LOCALE_SPANISH;
case QLocale::Swedish: return C_LOCALE_SWEDISH;
case QLocale::Thai: return C_LOCALE_THAI;
case QLocale::Turkish: return C_LOCALE_TURKISH;
case QLocale::Ukrainian: return C_LOCALE_UKRAINIAN;
case QLocale::Uzbek: return C_LOCALE_UZBEK;
case QLocale::Vietnamese: return C_LOCALE_VIETNAMESE;
default:
const QString lang = QLocale::languageToString(locale.language());
qWarning() << "Unrecognized language name: " << lang;
return lang;
}
}
QString Utils::Misc::parseHtmlLinks(const QString &rawText) QString Utils::Misc::parseHtmlLinks(const QString &rawText)
{ {
QString result = rawText; QString result = rawText;

View file

@ -85,6 +85,8 @@ namespace Utils::Misc
QString userFriendlyDuration(qlonglong seconds, qlonglong maxCap = -1); QString userFriendlyDuration(qlonglong seconds, qlonglong maxCap = -1);
QString getUserIDString(); QString getUserIDString();
QString languageToLocalizedString(const QString &localeStr);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
Path windowsSystemPath(); Path windowsSystemPath();

View file

@ -52,8 +52,8 @@
#include "base/rss/rss_session.h" #include "base/rss/rss_session.h"
#include "base/torrentfileguard.h" #include "base/torrentfileguard.h"
#include "base/torrentfileswatcher.h" #include "base/torrentfileswatcher.h"
#include "base/unicodestrings.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/net.h" #include "base/utils/net.h"
#include "base/utils/password.h" #include "base/utils/password.h"
#include "base/utils/random.h" #include "base/utils/random.h"
@ -89,81 +89,6 @@ namespace
return ret; return ret;
} }
QString languageToLocalizedString(const QLocale &locale)
{
switch (locale.language())
{
case QLocale::Arabic: return C_LOCALE_ARABIC;
case QLocale::Armenian: return C_LOCALE_ARMENIAN;
case QLocale::Azerbaijani: return C_LOCALE_AZERBAIJANI;
case QLocale::Basque: return C_LOCALE_BASQUE;
case QLocale::Bulgarian: return C_LOCALE_BULGARIAN;
case QLocale::Byelorussian: return C_LOCALE_BYELORUSSIAN;
case QLocale::Catalan: return C_LOCALE_CATALAN;
case QLocale::Chinese:
switch (locale.country())
{
case QLocale::China: return C_LOCALE_CHINESE_SIMPLIFIED;
case QLocale::HongKong: return C_LOCALE_CHINESE_TRADITIONAL_HK;
default: return C_LOCALE_CHINESE_TRADITIONAL_TW;
}
case QLocale::Croatian: return C_LOCALE_CROATIAN;
case QLocale::Czech: return C_LOCALE_CZECH;
case QLocale::Danish: return C_LOCALE_DANISH;
case QLocale::Dutch: return C_LOCALE_DUTCH;
case QLocale::English:
switch (locale.country())
{
case QLocale::Australia: return C_LOCALE_ENGLISH_AUSTRALIA;
case QLocale::UnitedKingdom: return C_LOCALE_ENGLISH_UNITEDKINGDOM;
default: return C_LOCALE_ENGLISH;
}
case QLocale::Estonian: return C_LOCALE_ESTONIAN;
case QLocale::Finnish: return C_LOCALE_FINNISH;
case QLocale::French: return C_LOCALE_FRENCH;
case QLocale::Galician: return C_LOCALE_GALICIAN;
case QLocale::Georgian: return C_LOCALE_GEORGIAN;
case QLocale::German: return C_LOCALE_GERMAN;
case QLocale::Greek: return C_LOCALE_GREEK;
case QLocale::Hebrew: return C_LOCALE_HEBREW;
case QLocale::Hindi: return C_LOCALE_HINDI;
case QLocale::Hungarian: return C_LOCALE_HUNGARIAN;
case QLocale::Icelandic: return C_LOCALE_ICELANDIC;
case QLocale::Indonesian: return C_LOCALE_INDONESIAN;
case QLocale::Italian: return C_LOCALE_ITALIAN;
case QLocale::Japanese: return C_LOCALE_JAPANESE;
case QLocale::Korean: return C_LOCALE_KOREAN;
case QLocale::Latvian: return C_LOCALE_LATVIAN;
case QLocale::Lithuanian: return C_LOCALE_LITHUANIAN;
case QLocale::Malay: return C_LOCALE_MALAY;
case QLocale::Mongolian: return C_LOCALE_MONGOLIAN;
case QLocale::NorwegianBokmal: return C_LOCALE_NORWEGIAN;
case QLocale::Occitan: return C_LOCALE_OCCITAN;
case QLocale::Persian: return C_LOCALE_PERSIAN;
case QLocale::Polish: return C_LOCALE_POLISH;
case QLocale::Portuguese:
if (locale.country() == QLocale::Brazil)
return C_LOCALE_PORTUGUESE_BRAZIL;
return C_LOCALE_PORTUGUESE;
case QLocale::Romanian: return C_LOCALE_ROMANIAN;
case QLocale::Russian: return C_LOCALE_RUSSIAN;
case QLocale::Serbian: return C_LOCALE_SERBIAN;
case QLocale::Slovak: return C_LOCALE_SLOVAK;
case QLocale::Slovenian: return C_LOCALE_SLOVENIAN;
case QLocale::Spanish: return C_LOCALE_SPANISH;
case QLocale::Swedish: return C_LOCALE_SWEDISH;
case QLocale::Thai: return C_LOCALE_THAI;
case QLocale::Turkish: return C_LOCALE_TURKISH;
case QLocale::Ukrainian: return C_LOCALE_UKRAINIAN;
case QLocale::Uzbek: return C_LOCALE_UZBEK;
case QLocale::Vietnamese: return C_LOCALE_VIETNAMESE;
default:
const QString lang = QLocale::languageToString(locale.language());
qWarning() << "Unrecognized language name: " << lang;
return lang;
}
}
class WheelEventEater final : public QObject class WheelEventEater final : public QObject
{ {
public: public:
@ -1326,25 +1251,8 @@ void OptionsDialog::initializeLanguageCombo()
const QStringList langFiles = langDir.entryList(QStringList(u"qbittorrent_*.qm"_qs), QDir::Files); const QStringList langFiles = langDir.entryList(QStringList(u"qbittorrent_*.qm"_qs), QDir::Files);
for (const QString &langFile : langFiles) for (const QString &langFile : langFiles)
{ {
QString localeStr = langFile.mid(12); // remove "qbittorrent_" const QString localeStr = langFile.section(u"_"_qs, 1, -1).section(u"."_qs, 0, 0); // remove "qbittorrent_" and ".qm"
localeStr.chop(3); // Remove ".qm" m_ui->comboI18n->addItem(/*QIcon(":/icons/flags/"+country+".svg"), */ Utils::Misc::languageToLocalizedString(localeStr), localeStr);
QString languageName;
if (localeStr.startsWith(u"eo", Qt::CaseInsensitive))
{
// QLocale doesn't work with that locale. Esperanto isn't a "real" language.
languageName = C_LOCALE_ESPERANTO;
}
else if (localeStr.startsWith(u"ltg", Qt::CaseInsensitive))
{
// QLocale doesn't work with that locale.
languageName = C_LOCALE_LATGALIAN;
}
else
{
QLocale locale(localeStr);
languageName = languageToLocalizedString(locale);
}
m_ui->comboI18n->addItem(/*QIcon(":/icons/flags/"+country+".svg"), */ languageName, localeStr);
qDebug() << "Supported locale:" << localeStr; qDebug() << "Supported locale:" << localeStr;
} }
} }

View file

@ -32,6 +32,7 @@
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QJsonDocument> #include <QJsonDocument>
@ -112,6 +113,22 @@ namespace
return u"no-store"_qs; return u"no-store"_qs;
} }
QString createLanguagesOptionsHtml()
{
// List language files
const QDir langDir {u":/www/translations"_qs};
const QStringList langFiles = langDir.entryList(QStringList(u"webui_*.qm"_qs), QDir::Files);
QStringList languages;
for (const QString &langFile : langFiles)
{
const QString localeStr = langFile.section(u"_"_qs, 1, -1).section(u"."_qs, 0, 0); // remove "webui_" and ".qm"
languages << u"<option value=\"%1\">%2</option>"_qs.arg(localeStr, Utils::Misc::languageToLocalizedString(localeStr));
qDebug() << "Supported locale:" << localeStr;
}
return languages.join(u'\n');
}
} }
WebApplication::WebApplication(IApplication *app, QObject *parent) WebApplication::WebApplication(IApplication *app, QObject *parent)
@ -472,13 +489,17 @@ void WebApplication::sendFile(const Path &path)
const QMimeType mimeType = QMimeDatabase().mimeTypeForFileNameAndData(path.data(), data); const QMimeType mimeType = QMimeDatabase().mimeTypeForFileNameAndData(path.data(), data);
const bool isTranslatable = !m_isAltUIUsed && mimeType.inherits(u"text/plain"_qs); const bool isTranslatable = !m_isAltUIUsed && mimeType.inherits(u"text/plain"_qs);
// Translate the file
if (isTranslatable) if (isTranslatable)
{ {
auto dataStr = QString::fromUtf8(data); auto dataStr = QString::fromUtf8(data);
// Translate the file
translateDocument(dataStr); translateDocument(dataStr);
data = dataStr.toUtf8();
// Add the language options
if (path == (m_rootFolder / Path(PRIVATE_FOLDER) / Path(u"views/preferences.html"_qs)))
dataStr.replace(u"${LANGUAGE_OPTIONS}"_qs, createLanguagesOptionsHtml());
data = dataStr.toUtf8();
m_translatedFiles[path] = {data, mimeType.name(), lastModified}; // caching translated file m_translatedFiles[path] = {data, mimeType.name(), lastModified}; // caching translated file
} }

View file

@ -666,62 +666,7 @@
<legend>QBT_TR(Language)QBT_TR[CONTEXT=OptionsDialog]</legend> <legend>QBT_TR(Language)QBT_TR[CONTEXT=OptionsDialog]</legend>
<label for="locale_select">QBT_TR(User Interface Language:)QBT_TR[CONTEXT=OptionsDialog]</label> <label for="locale_select">QBT_TR(User Interface Language:)QBT_TR[CONTEXT=OptionsDialog]</label>
<select id="locale_select"> <select id="locale_select">
<option value="ar_AE">عربي</option> ${LANGUAGE_OPTIONS}
<option value="az@latin">Azərbaycan dili</option>
<option value="be_BY">Беларуская</option>
<option value="bg_BG">Български</option>
<option value="ca_ES">Català</option>
<option value="cs_CZ">Čeština</option>
<option value="da_DK">Dansk</option>
<option value="de_DE">Deutsch</option>
<option value="el_GR">Ελληνικά</option>
<option value="en">English</option>
<option value="en_AU">English (Australia)</option>
<option value="en_GB">English (United Kingdom)</option>
<option value="eo_EO">Esperanto</option>
<option value="es_ES">Español</option>
<option value="et">Eesti, eesti keel</option>
<option value="eu_ES">Euskara</option>
<option value="fa">فارسی</option>
<option value="fi_FI">Suomi</option>
<option value="fr_FR">Français</option>
<option value="gl_ES">Galego</option>
<option value="he_IL">עברית</option>
<option value="hi_IN">हिन्दी, हिंदी</option>
<option value="hr_HR">Hrvatski</option>
<option value="hu_HU">Magyar</option>
<option value="hy_AM">Հայերեն</option>
<option value="id">Bahasa Indonesia</option>
<option value="is">Íslenska</option>
<option value="it_IT">Italiano</option>
<option value="ja_JP">日本語</option>
<option value="ka_GE">ქართული</option>
<option value="ko_KR">한국어</option>
<option value="ltg">Latgalīšu volūda</option>
<option value="lt_LT">Lietuvių</option>
<option value="lv_LV">Latviešu valoda</option>
<option value="mn_MN">Монгол хэл</option>
<option value="ms_MY">بهاس ملايو</option>
<option value="nb_NO">Norsk</option>
<option value="nl_NL">Nederlands</option>
<option value="oc">lenga d'òc</option>
<option value="pl_PL">Polski</option>
<option value="pt_BR">Português brasileiro</option>
<option value="pt_PT">Português</option>
<option value="ro_RO">Română</option>
<option value="ru_RU">Русский</option>
<option value="sk_SK">Slovenčina</option>
<option value="sl_SI">Slovenščina</option>
<option value="sr_CS">Српски</option>
<option value="sv_SE">Svenska</option>
<option value="th">ไทย</option>
<option value="tr_TR">Türkçe</option>
<option value="uk_UA">Українська</option>
<option value="uz@Latn">أۇزبېك</option>
<option value="vi_VN">Tiếng Việt</option>
<option value="zh">简体中文</option>
<option value="zh_HK">香港正體字</option>
<option value="zh_TW">正體中文</option>
</select> </select>
</fieldset> </fieldset>
@ -1408,6 +1353,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
updateWebUICustomHTTPHeadersSettings: updateWebUICustomHTTPHeadersSettings, updateWebUICustomHTTPHeadersSettings: updateWebUICustomHTTPHeadersSettings,
updateWebUIReverseProxySettings: updateWebUIReverseProxySettings, updateWebUIReverseProxySettings: updateWebUIReverseProxySettings,
updateDynDnsSettings: updateDynDnsSettings, updateDynDnsSettings: updateDynDnsSettings,
updateWebuiLocaleSelect: updateWebuiLocaleSelect,
registerDynDns: registerDynDns, registerDynDns: registerDynDns,
applyPreferences: applyPreferences applyPreferences: applyPreferences
}; };
@ -1737,6 +1683,18 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
}).send(); }).send();
}; };
const updateWebuiLocaleSelect = (selected) => {
let languages = [];
for (let i = 0; i < $('locale_select').options.length; i++)
languages.push($('locale_select').options[i].value);
if (!languages.includes(selected)) {
const lang = selected.slice(0, selected.indexOf('_'));
selected = languages.includes(lang) ? lang : 'en';
}
$('locale_select').setProperty('value', selected);
};
const loadPreferences = function() { const loadPreferences = function() {
const url = 'api/v2/app/preferences'; const url = 'api/v2/app/preferences';
new Request.JSON({ new Request.JSON({
@ -2013,7 +1971,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
// Web UI tab // Web UI tab
// Language // Language
$('locale_select').setProperty('value', ((pref.locale === "en_US") ? "en" : pref.locale)); updateWebuiLocaleSelect(pref.locale);
$('performanceWarning').setProperty('checked', pref.performance_warning); $('performanceWarning').setProperty('checked', pref.performance_warning);
// HTTP Server // HTTP Server