From 73cf41b81eff019478114d869ee196d1e7d7ee17 Mon Sep 17 00:00:00 2001 From: a1ext Date: Sun, 20 Jan 2019 20:00:23 +0300 Subject: [PATCH] Translations deployment for MAC & Linux has fixed (#1119) * Translations load refactoring * Translations: Added MAC support * Translations: fixed getting of translation folders * Fixed code style, documented some methods --- .travis.yml | 5 + src/CutterApplication.cpp | 101 +++++++++++------- src/CutterApplication.h | 7 ++ src/Main.cpp | 4 + src/common/Configuration.cpp | 57 ++++++++-- src/common/Configuration.h | 9 +- src/dialogs/WelcomeDialog.cpp | 1 + .../preferences/AppearanceOptionsWidget.cpp | 14 +-- src/dialogs/preferences/PreferencesDialog.cpp | 1 + 9 files changed, 140 insertions(+), 59 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9fe3574a..18f8d818 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,10 @@ script: after_success: - export CUTTER_VERSION=$(python ../scripts/get_version.py) + - lrelease ../src/Cutter.pro - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + mkdir -p Cutter.app/Contents/Resources/translations && + cp ../src/translations/*.qm Cutter.app/Contents/Resources/translations/ && macdeployqt Cutter.app -executable=Cutter.app/Contents/MacOS/Cutter -libpath="../Frameworks" && macdeployqt Cutter.app -executable=Cutter.app/Contents/MacOS/Cutter -libpath="../Frameworks" && "$TRAVIS_BUILD_DIR/scripts/appbundle_embed_python.sh" "$PYTHON_FRAMEWORK_DIR/Python.framework" Cutter.app Cutter.app/Contents/MacOS/Cutter && @@ -98,6 +101,8 @@ after_success: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make INSTALL_ROOT=appdir install && cp -r /usr/share/radare2 appdir/usr/share/ && + mkdir -p appdir/usr/bin/translations && + cp ../src/translations/*.qm appdir/usr/bin/translations/ && "$TRAVIS_BUILD_DIR/scripts/appimage_embed_python.sh" "$CUSTOM_PYTHON_PREFIX" appdir && wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" && chmod a+x linuxdeployqt*.AppImage && diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index c70a224f..0129ac77 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -25,8 +25,6 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv) { // Setup application information - setOrganizationName("Cutter"); - setApplicationName("Cutter"); setApplicationVersion(CUTTER_VERSION_FULL); setWindowIcon(QIcon(":/img/cutter.svg")); setAttribute(Qt::AA_DontShowIconsInMenus); @@ -34,45 +32,10 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc // WARN!!! Put initialization code below this line. Code above this line is mandatory to be run First // Load translations - QTranslator *t = new QTranslator; - QTranslator *qtBaseTranslator = new QTranslator; - QTranslator *qtTranslator = new QTranslator; - QString language = Config()->getCurrLocale().bcp47Name(); - auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, - QLocale::AnyCountry); - - QString langPrefix; - if (language != "en") { - for (const QLocale &it : allLocales) { - langPrefix = it.bcp47Name(); - if (langPrefix == language) { - const QString &cutterTranslationPath = QCoreApplication::applicationDirPath() + QDir::separator() - + "translations" + QDir::separator() + QString("cutter_%1.qm").arg(langPrefix); - - if (t->load(cutterTranslationPath)) { - installTranslator(t); - } - QApplication::setLayoutDirection(it.textDirection()); - QLocale::setDefault(it); - - QString translationsPath(QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - if (qtTranslator->load(it, "qt", "_", translationsPath)) { - installTranslator(qtTranslator); - } else { - delete qtTranslator; - } - - if (qtBaseTranslator->load(it, "qtbase", "_", translationsPath)) { - installTranslator(qtBaseTranslator); - } else { - delete qtBaseTranslator; - } - - break; - } - } + if (!loadTranslations()) { + qWarning() << "Cannot load translations"; } - + // Load fonts int ret = QFontDatabase::addApplicationFont(":/fonts/Anonymous Pro.ttf"); if (ret == -1) { @@ -264,3 +227,61 @@ void CutterApplication::loadPlugins() Core()->setCutterPlugins(plugins); } + +bool CutterApplication::loadTranslations() +{ + const QString &language = Config()->getCurrLocale().bcp47Name(); + if (language == QStringLiteral("en") || language.startsWith(QStringLiteral("en-"))) { + return true; + } + const auto &allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, + QLocale::AnyCountry); + + bool cutterTrLoaded = false; + + for (const QLocale &it : allLocales) { + const QString &langPrefix = it.bcp47Name(); + if (langPrefix == language) { + QApplication::setLayoutDirection(it.textDirection()); + QLocale::setDefault(it); + + QTranslator *trCutter = new QTranslator; + QTranslator *trQtBase = new QTranslator; + QTranslator *trQt = new QTranslator; + + const QStringList &cutterTrPaths = Config()->getTranslationsDirectories(); + + for (const auto &trPath : cutterTrPaths) { + if (trCutter && trCutter->load(it, QLatin1String("cutter"), QLatin1String("_"), trPath)) { + installTranslator(trCutter); + cutterTrLoaded = true; + trCutter = nullptr; + } + if (trQt && trQt->load(it, "qt", "_", trPath)) { + installTranslator(trQt); + trQt = nullptr; + } + + if (trQtBase && trQtBase->load(it, "qtbase", "_", trPath)) { + installTranslator(trQtBase); + trQtBase = nullptr; + } + } + + if (trCutter) { + delete trCutter; + } + if (trQt) { + delete trQt; + } + if (trQtBase) { + delete trQtBase; + } + return true; + } + } + if (!cutterTrLoaded) { + qWarning() << "Cannot load Cutter's translation for " << language; + } + return false; +} \ No newline at end of file diff --git a/src/CutterApplication.h b/src/CutterApplication.h index 703b4619..dc7c5ac9 100644 --- a/src/CutterApplication.h +++ b/src/CutterApplication.h @@ -26,6 +26,13 @@ public: protected: bool event(QEvent *e); +private: + /*! + * \brief Load and translations depending on Language settings + * \return true on success + */ + bool loadTranslations(); + private: bool m_FileAlreadyDropped; MainWindow *mainWindow; diff --git a/src/Main.cpp b/src/Main.cpp index a1672e3a..ccc7f3a0 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -7,6 +7,10 @@ int main(int argc, char *argv[]) qRegisterMetaType>(); qRegisterMetaType>(); + // Application info setup, required to be set before any instance of QSettings will be instantiated + QCoreApplication::setOrganizationName("Cutter"); + QCoreApplication::setApplicationName("Cutter"); + CutterApplication a(argc, argv); int ret = a.exec(); diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index d06b81de..d2181fad 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "common/ColorSchemeFileSaver.h" @@ -54,6 +55,13 @@ static const QHash asmOptions = { Configuration::Configuration() : QObject() { mPtr = this; + if (!s.isWritable()) { + QMessageBox::critical(nullptr, + tr("Critical!"), + tr("!!! Settings are not writable! Make sure you have a write access to \"%1\"") + .arg(s.fileName()) + ); + } loadInitial(); } @@ -74,7 +82,7 @@ void Configuration::loadInitial() QString Configuration::getDirProjects() { auto projectsDir = s.value("dir.projects").toString(); - if (projectsDir == "") { + if (projectsDir.isEmpty()) { projectsDir = Core()->getConfig("dir.projects"); setDirProjects(projectsDir); } @@ -126,7 +134,7 @@ QLocale Configuration::getCurrLocale() const /*! * \brief sets Cutter's locale - * \param l - a QLocale object describes the locate to confugre + * \param l - a QLocale object describes the locate to configure */ void Configuration::setLocale(const QLocale &l) { @@ -136,18 +144,20 @@ void Configuration::setLocale(const QLocale &l) /*! * \brief set Cutter's interface language by a given locale name * \param language - a string represents the name of a locale language + * \return true on success */ -void Configuration::setLocaleByName(const QString &language) +bool Configuration::setLocaleByName(const QString &language) { - auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, + const auto &allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); for (auto &it : allLocales) { if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0) { setLocale(it); - break; + return true; } } + return false; } bool Configuration::windowColorIsDark() @@ -454,10 +464,23 @@ void Configuration::setConfig(const QString &key, const QVariant &value) */ QStringList Configuration::getAvailableTranslations() { - QDir dir(QCoreApplication::applicationDirPath() + QDir::separator() + - "translations"); - QStringList fileNames = dir.entryList(QStringList("cutter_*.qm"), QDir::Files, - QDir::Name); + const auto &trDirs = getTranslationsDirectories(); + + QSet fileNamesSet; + for (const auto &trDir : trDirs) { + QDir dir(trDir); + if (!dir.exists()) { + continue; + } + const QStringList &currTrFileNames = dir.entryList(QStringList("cutter_*.qm"), QDir::Files, + QDir::Name); + for (const auto &trFile : currTrFileNames) { + fileNamesSet << trFile; + } + } + + QStringList fileNames = fileNamesSet.toList(); + qSort(fileNames); QStringList languages; QString currLanguageName; auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, @@ -475,7 +498,7 @@ QStringList Configuration::getAvailableTranslations() } } } - return languages << "English"; + return languages << QLatin1String("English"); } /*! @@ -492,3 +515,17 @@ bool Configuration::isFirstExecution() return true; } } + +QStringList Configuration::getTranslationsDirectories() const +{ + static const QString cutterTranslationPath = QCoreApplication::applicationDirPath() + QDir::separator() + + QLatin1String("translations"); + + return { + cutterTranslationPath, + QLibraryInfo::location(QLibraryInfo::TranslationsPath), +#ifdef Q_OS_MAC + QStringLiteral("%1/../Resources/translations").arg(QCoreApplication::applicationDirPath()), +#endif // Q_OS_MAC + }; +} diff --git a/src/common/Configuration.h b/src/common/Configuration.h index 4cb95b53..c2b88f62 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -50,7 +50,7 @@ public: // Languages QLocale getCurrLocale() const; void setLocale(const QLocale &l); - void setLocaleByName(const QString &language); + bool setLocaleByName(const QString &language); QStringList getAvailableTranslations(); // Fonts @@ -107,7 +107,12 @@ public: */ void setConfig(const QString &key, const QVariant &value); bool isFirstExecution(); - + + /*! + * \brief Get list of available translation directories (depends on configuration and OS) + * \return list of directories + */ + QStringList getTranslationsDirectories() const; signals: void fontsUpdated(); diff --git a/src/dialogs/WelcomeDialog.cpp b/src/dialogs/WelcomeDialog.cpp index 18b4f593..73ef178d 100644 --- a/src/dialogs/WelcomeDialog.cpp +++ b/src/dialogs/WelcomeDialog.cpp @@ -16,6 +16,7 @@ WelcomeDialog::WelcomeDialog(QWidget *parent) : ui(new Ui::WelcomeDialog) { ui->setupUi(this); + setWindowFlag(Qt::WindowContextHelpButtonHint, false); ui->logoSvgWidget->load(Config()->getLogoFile()); ui->versionLabel->setText("" + tr("Version ") + CUTTER_VERSION_FULL + ""); ui->themeComboBox->setCurrentIndex(Config()->getTheme()); diff --git a/src/dialogs/preferences/AppearanceOptionsWidget.cpp b/src/dialogs/preferences/AppearanceOptionsWidget.cpp index 5227965a..f3f6f1ce 100644 --- a/src/dialogs/preferences/AppearanceOptionsWidget.cpp +++ b/src/dialogs/preferences/AppearanceOptionsWidget.cpp @@ -185,12 +185,12 @@ void AppearanceOptionsWidget::on_deleteButton_clicked() void AppearanceOptionsWidget::onLanguageComboBoxCurrentIndexChanged(int index) { QString language = ui->languageComboBox->itemText(index).toLower(); - Config()->setLocaleByName(language); + if (Config()->setLocaleByName(language)) { + QMessageBox::information(this, + tr("Language settings"), + tr("Language will be changed after next application start.")); + return; + } - QMessageBox mb; - mb.setWindowTitle(tr("Language settings")); - mb.setText(tr("Language will be changed after next application start.")); - mb.setIcon(QMessageBox::Information); - mb.setStandardButtons(QMessageBox::Ok); - mb.exec(); + qWarning() << tr("Cannot set language, not found in available ones"); } diff --git a/src/dialogs/preferences/PreferencesDialog.cpp b/src/dialogs/preferences/PreferencesDialog.cpp index b076ce35..1e874527 100644 --- a/src/dialogs/preferences/PreferencesDialog.cpp +++ b/src/dialogs/preferences/PreferencesDialog.cpp @@ -20,6 +20,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); + setWindowFlag(Qt::WindowContextHelpButtonHint, false); QList prefs {