diff --git a/.gitignore b/.gitignore index 8ed956f27..20862ab58 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ qrc_*.cpp ui_*.h *.moc src/lang/qbittorrent_*.qm +src/webui/www/translations/webui_*.qm .DS_Store .qmake.stash src/qbittorrent.app diff --git a/src/lang/lang.pri b/src/lang/lang.pri index 30d5b7106..504deced2 100644 --- a/src/lang/lang.pri +++ b/src/lang/lang.pri @@ -7,14 +7,15 @@ for(file, TS_FILES) { } isEmpty(QMAKE_LRELEASE) { - win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\\lrelease.exe - else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease + win32: QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease.exe + else: QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease unix { - equals(QT_MAJOR_VERSION, 5) { - !exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease-qt5 } - } - } else { - !exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease } + equals(QT_MAJOR_VERSION, 5) { + !exists($$QMAKE_LRELEASE): QMAKE_LRELEASE = lrelease-qt5 + } + } + else { + !exists($$QMAKE_LRELEASE): QMAKE_LRELEASE = lrelease } } diff --git a/src/webui/CMakeLists.txt b/src/webui/CMakeLists.txt index 0f3471168..5c4ae7f71 100644 --- a/src/webui/CMakeLists.txt +++ b/src/webui/CMakeLists.txt @@ -11,7 +11,6 @@ api/synccontroller.h api/torrentscontroller.h api/transfercontroller.h api/serialize/serialize_torrent.h -extra_translations.h webapplication.h webui.h diff --git a/src/webui/extra_translations.h b/src/webui/extra_translations.h deleted file mode 100644 index 2d8ce1123..000000000 --- a/src/webui/extra_translations.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2014 Vladimir Golovnev - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -#ifndef EXTRA_TRANSLATIONS_H -#define EXTRA_TRANSLATIONS_H - -#include - -// Additional translations for Web UI -const char *QBT_WEBUI_TRANSLATIONS[] = { - QT_TRANSLATE_NOOP("HttpServer", "Logout"), - QT_TRANSLATE_NOOP("HttpServer", "Exit qBittorrent"), - QT_TRANSLATE_NOOP("HttpServer", "Download Torrents from their URLs or Magnet links"), - QT_TRANSLATE_NOOP("HttpServer", "Only one link per line"), - QT_TRANSLATE_NOOP("HttpServer", "Upload local torrent"), - QT_TRANSLATE_NOOP("HttpServer", "Are you sure you want to delete the selected torrents from the transfer list?"), - QT_TRANSLATE_NOOP("HttpServer", "Global upload rate limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Global download rate limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Alternative upload rate limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Alternative download rate limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Maximum active downloads must be greater than -1."), - QT_TRANSLATE_NOOP("HttpServer", "Maximum active uploads must be greater than -1."), - QT_TRANSLATE_NOOP("HttpServer", "Maximum active torrents must be greater than -1."), - QT_TRANSLATE_NOOP("HttpServer", "Maximum number of connections limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Maximum number of connections per torrent limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Maximum number of upload slots per torrent limit must be greater than 0 or disabled."), - QT_TRANSLATE_NOOP("HttpServer", "Unable to save program preferences, qBittorrent is probably unreachable."), - QT_TRANSLATE_NOOP("HttpServer", "The port used for incoming connections must be between 1 and 65535."), - QT_TRANSLATE_NOOP("HttpServer", "The port used for the Web UI must be between 1 and 65535."), - QT_TRANSLATE_NOOP("HttpServer", "Save"), - QT_TRANSLATE_NOOP("HttpServer", "qBittorrent client is not reachable"), - QT_TRANSLATE_NOOP("HttpServer", "qBittorrent has been shutdown."), - QT_TRANSLATE_NOOP("HttpServer", "Unable to log in, qBittorrent is probably unreachable."), - QT_TRANSLATE_NOOP("HttpServer", "Invalid Username or Password."), - QT_TRANSLATE_NOOP("HttpServer", "Username"), - QT_TRANSLATE_NOOP("HttpServer", "Password"), - QT_TRANSLATE_NOOP("HttpServer", "Login"), - QT_TRANSLATE_NOOP("HttpServer", "Original authors"), - QT_TRANSLATE_NOOP("HttpServer", "Apply"), - QT_TRANSLATE_NOOP("HttpServer", "Add"), - QT_TRANSLATE_NOOP("HttpServer", "Save files to location:"), - QT_TRANSLATE_NOOP("HttpServer", "Cookie:"), - QT_TRANSLATE_NOOP("HttpServer", "Type folder here"), - QT_TRANSLATE_NOOP("HttpServer", "More information"), - QT_TRANSLATE_NOOP("HttpServer", "Information about certificates"), - QT_TRANSLATE_NOOP("HttpServer", "Save Files to"), - QT_TRANSLATE_NOOP("HttpServer", "IRC: #qbittorrent on Freenode"), - QT_TRANSLATE_NOOP("HttpServer", "Invalid category name:\nPlease do not use any special characters in the category name."), - QT_TRANSLATE_NOOP("HttpServer", "Unknown"), - QT_TRANSLATE_NOOP("HttpServer", "Hard Disk"), - QT_TRANSLATE_NOOP("HttpServer", "Share ratio limit must be between 0 and 9998."), - QT_TRANSLATE_NOOP("HttpServer", "Seeding time limit must be between 0 and 525600 minutes."), - QT_TRANSLATE_NOOP("HttpServer", "Set location"), - QT_TRANSLATE_NOOP("HttpServer", "Limit upload rate"), - QT_TRANSLATE_NOOP("HttpServer", "Limit download rate"), - QT_TRANSLATE_NOOP("HttpServer", "Rename torrent"), - QT_TRANSLATE_NOOP("HttpServer", "Unable to create category") -}; - -const struct { const char *source; const char *comment; } QBT_WEBUI_COMMENTED_TRANSLATIONS[] = { - QT_TRANSLATE_NOOP3("HttpServer", "Other...", "Save Files to: Watch Folder / Default Folder / Other..."), - QT_TRANSLATE_NOOP3("HttpServer", "Monday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Tuesday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Wednesday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Thursday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Friday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Saturday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Sunday", "Schedule the use of alternative rate limits on ..."), - QT_TRANSLATE_NOOP3("HttpServer", "Upload Torrents", "Upload torrent files to qBittorent using WebUI") -}; - -#endif // EXTRA_TRANSLATIONS_H diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 828be87e5..440d30b1d 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -34,7 +34,6 @@ #include #include -#include #include #include #include @@ -91,46 +90,6 @@ namespace return ret; } - void translateDocument(const QString &locale, QString &data) - { - const QRegularExpression regex("QBT_TR\\((([^\\)]|\\)(?!QBT_TR))+)\\)QBT_TR(\\[CONTEXT=([a-zA-Z_][a-zA-Z0-9_]*)\\])"); - const QRegularExpression mnemonic("\\(?&([a-zA-Z]?\\))?"); - - const bool isTranslationNeeded = !locale.startsWith("en") - || locale.startsWith("en_AU") || locale.startsWith("en_GB"); - - int i = 0; - bool found = true; - while (i < data.size() && found) { - QRegularExpressionMatch regexMatch; - i = data.indexOf(regex, i, ®exMatch); - if (i >= 0) { - const QString word = regexMatch.captured(1); - const QString context = regexMatch.captured(4); - - QString translation = isTranslationNeeded - ? qApp->translate(context.toUtf8().constData(), word.toUtf8().constData(), nullptr, 1) - : word; - - // Remove keyboard shortcuts - translation.remove(mnemonic); - - // Use HTML code for quotes to prevent issues with JS - translation.replace('\'', "'"); - translation.replace('\"', """); - - data.replace(i, regexMatch.capturedLength(), translation); - i += translation.length(); - } - else { - found = false; // no more translatable strings - } - - data.replace(QLatin1String("${LANG}"), locale.left(2)); - data.replace(QLatin1String("${VERSION}"), QBT_VERSION); - } - } - inline QUrl urlFromHostHeader(const QString &hostHeader) { if (!hostHeader.contains(QLatin1String("://"))) @@ -234,6 +193,43 @@ void WebApplication::sendWebUIFile() sendFile(localPath); } +void WebApplication::translateDocument(QString &data) +{ + const QRegularExpression regex("QBT_TR\\((([^\\)]|\\)(?!QBT_TR))+)\\)QBT_TR\\[CONTEXT=([a-zA-Z_][a-zA-Z0-9_]*)\\]"); + + const bool isTranslationNeeded = !m_currentLocale.startsWith("en") + || m_currentLocale.startsWith("en_AU") || m_currentLocale.startsWith("en_GB") + || !m_translator.isEmpty(); + + int i = 0; + bool found = true; + while (i < data.size() && found) { + QRegularExpressionMatch regexMatch; + i = data.indexOf(regex, i, ®exMatch); + if (i >= 0) { + const QString word = regexMatch.captured(1); + const QString context = regexMatch.captured(3); + + QString translation = isTranslationNeeded + ? m_translator.translate(context.toUtf8().constData(), word.toUtf8().constData(), nullptr, 1) + : word; + + // Use HTML code for quotes to prevent issues with JS + translation.replace('\'', "'"); + translation.replace('\"', """); + + data.replace(i, regexMatch.capturedLength(), translation); + i += translation.length(); + } + else { + found = false; // no more translatable strings + } + + data.replace(QLatin1String("${LANG}"), m_currentLocale.left(2)); + data.replace(QLatin1String("${VERSION}"), QBT_VERSION); + } +} + WebSession *WebApplication::session() { return m_currentSession; @@ -429,6 +425,14 @@ void WebApplication::configure() if (m_currentLocale != newLocale) { m_currentLocale = newLocale; m_translatedFiles.clear(); + if (m_translator.load(m_rootFolder + QLatin1String("/translations/webui_") + m_currentLocale)) { + LogMsg(tr("WebUI translation for selected locale (%1) is successfully loaded.") + .arg(m_currentLocale)); + } + else { + LogMsg(tr("Couldn't load WebUI translation for selected locale (%1). Falling back to default (en).") + .arg(m_currentLocale), Log::WARNING); + } } m_isLocalAuthEnabled = pref->isWebUiLocalAuthEnabled(); @@ -490,7 +494,7 @@ void WebApplication::sendFile(const QString &path) // Translate the file if (isTranslatable) { QString dataStr {data}; - translateDocument(m_currentLocale, dataStr); + translateDocument(dataStr); data = dataStr.toUtf8(); m_translatedFiles[path] = {data, lastModified}; // caching translated file diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index 0de4ad9f3..ebcf21db1 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "api/isessionmanager.h" #include "base/http/irequesthandler.h" @@ -109,6 +110,8 @@ private: void sendFile(const QString &path); void sendWebUIFile(); + void translateDocument(QString &data); + // Session management QString generateSid() const; void sessionInitialize(); @@ -142,6 +145,7 @@ private: }; QMap m_translatedFiles; QString m_currentLocale; + QTranslator m_translator; bool m_isLocalAuthEnabled; bool m_isAuthSubnetWhitelistEnabled; diff --git a/src/webui/webui.pri b/src/webui/webui.pri index 2c960ca7c..bdf4aede3 100644 --- a/src/webui/webui.pri +++ b/src/webui/webui.pri @@ -10,7 +10,6 @@ HEADERS += \ $$PWD/api/torrentscontroller.h \ $$PWD/api/transfercontroller.h \ $$PWD/api/serialize/serialize_torrent.h \ - $$PWD/extra_translations.h \ $$PWD/webapplication.h \ $$PWD/webui.h @@ -29,3 +28,25 @@ SOURCES += \ $$PWD/webui.cpp RESOURCES += $$PWD/www/webui.qrc + +# WebUI Translation +isEmpty(QMAKE_LRELEASE) { + win32: QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease.exe + else: QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease + unix { + equals(QT_MAJOR_VERSION, 5) { + !exists($$QMAKE_LRELEASE): QMAKE_LRELEASE = lrelease-qt5 + } + } + else { + !exists($$QMAKE_LRELEASE): QMAKE_LRELEASE = lrelease + } +} +WEBUI_TRANSLATIONS = $$files(www/translations/webui_*.ts) +WEBUI_TRANSLATIONS_NOEXT = $$replace(WEBUI_TRANSLATIONS, ".ts", "") +message("Building WebUI translations...") +for(L, WEBUI_TRANSLATIONS_NOEXT) { + message("Processing $${L}") + system("$$QMAKE_LRELEASE -silent $${L}.ts -qm $${L}.qm") + !exists("$${L}.qm"): error("Building WebUI translations failed, cannot continue!") +} diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 6b77ce9fe..f3f8148af 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -37,22 +37,22 @@
   - QBT_TR(Add Torrent &Link...)QBT_TR[CONTEXT=MainWindow] - QBT_TR(&Add Torrent File...)QBT_TR[CONTEXT=MainWindow] + QBT_TR(Add Torrent Link...)QBT_TR[CONTEXT=MainWindow] + QBT_TR(Add Torrent File...)QBT_TR[CONTEXT=MainWindow] QBT_TR(Delete)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(Resume)QBT_TR[CONTEXT=TransferListWidget] QBT_TR(Pause)QBT_TR[CONTEXT=TransferListWidget] diff --git a/src/webui/www/private/preferences_content.html b/src/webui/www/private/preferences_content.html index 17c13b536..4ec2b46b9 100644 --- a/src/webui/www/private/preferences_content.html +++ b/src/webui/www/private/preferences_content.html @@ -51,7 +51,7 @@
- +
@@ -74,7 +74,7 @@
- +
QBT_TR(Supported parameters (case sensitive):)QBT_TR[CONTEXT=OptionsDialog]
    @@ -192,7 +192,7 @@
    - +
    @@ -248,7 +248,7 @@
    - + QBT_TR(From:)QBT_TR[CONTEXT=OptionsDialog] : QBT_TR(To:)QBT_TR[CONTEXT=OptionsDialog] : @@ -299,7 +299,7 @@
    - +
    @@ -354,7 +354,7 @@
    - +
    @@ -426,7 +426,7 @@
    - +
    @@ -471,7 +471,7 @@
    - +