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
This commit is contained in:
a1ext 2019-01-20 20:00:23 +03:00 committed by Itay Cohen
parent 04ed78444d
commit 73cf41b81e
9 changed files with 140 additions and 59 deletions

View File

@ -75,7 +75,10 @@ script:
after_success: after_success:
- export CUTTER_VERSION=$(python ../scripts/get_version.py) - export CUTTER_VERSION=$(python ../scripts/get_version.py)
- lrelease ../src/Cutter.pro
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - 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" &&
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 && "$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 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
make INSTALL_ROOT=appdir install && make INSTALL_ROOT=appdir install &&
cp -r /usr/share/radare2 appdir/usr/share/ && 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 && "$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" && wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" &&
chmod a+x linuxdeployqt*.AppImage && chmod a+x linuxdeployqt*.AppImage &&

View File

@ -25,8 +25,6 @@
CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv) CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv)
{ {
// Setup application information // Setup application information
setOrganizationName("Cutter");
setApplicationName("Cutter");
setApplicationVersion(CUTTER_VERSION_FULL); setApplicationVersion(CUTTER_VERSION_FULL);
setWindowIcon(QIcon(":/img/cutter.svg")); setWindowIcon(QIcon(":/img/cutter.svg"));
setAttribute(Qt::AA_DontShowIconsInMenus); setAttribute(Qt::AA_DontShowIconsInMenus);
@ -34,43 +32,8 @@ 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 // WARN!!! Put initialization code below this line. Code above this line is mandatory to be run First
// Load translations // Load translations
QTranslator *t = new QTranslator; if (!loadTranslations()) {
QTranslator *qtBaseTranslator = new QTranslator; qWarning() << "Cannot load translations";
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;
}
}
} }
// Load fonts // Load fonts
@ -264,3 +227,61 @@ void CutterApplication::loadPlugins()
Core()->setCutterPlugins(plugins); 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;
}

View File

@ -26,6 +26,13 @@ public:
protected: protected:
bool event(QEvent *e); bool event(QEvent *e);
private:
/*!
* \brief Load and translations depending on Language settings
* \return true on success
*/
bool loadTranslations();
private: private:
bool m_FileAlreadyDropped; bool m_FileAlreadyDropped;
MainWindow *mainWindow; MainWindow *mainWindow;

View File

@ -7,6 +7,10 @@ int main(int argc, char *argv[])
qRegisterMetaType<QList<StringDescription>>(); qRegisterMetaType<QList<StringDescription>>();
qRegisterMetaType<QList<FunctionDescription>>(); qRegisterMetaType<QList<FunctionDescription>>();
// 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); CutterApplication a(argc, argv);
int ret = a.exec(); int ret = a.exec();

View File

@ -5,6 +5,7 @@
#include <QFontDatabase> #include <QFontDatabase>
#include <QFile> #include <QFile>
#include <QApplication> #include <QApplication>
#include <QLibraryInfo>
#include "common/ColorSchemeFileSaver.h" #include "common/ColorSchemeFileSaver.h"
@ -54,6 +55,13 @@ static const QHash<QString, QVariant> asmOptions = {
Configuration::Configuration() : QObject() Configuration::Configuration() : QObject()
{ {
mPtr = this; 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(); loadInitial();
} }
@ -74,7 +82,7 @@ void Configuration::loadInitial()
QString Configuration::getDirProjects() QString Configuration::getDirProjects()
{ {
auto projectsDir = s.value("dir.projects").toString(); auto projectsDir = s.value("dir.projects").toString();
if (projectsDir == "") { if (projectsDir.isEmpty()) {
projectsDir = Core()->getConfig("dir.projects"); projectsDir = Core()->getConfig("dir.projects");
setDirProjects(projectsDir); setDirProjects(projectsDir);
} }
@ -126,7 +134,7 @@ QLocale Configuration::getCurrLocale() const
/*! /*!
* \brief sets Cutter's locale * \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) 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 * \brief set Cutter's interface language by a given locale name
* \param language - a string represents the name of a locale language * \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); QLocale::AnyCountry);
for (auto &it : allLocales) { for (auto &it : allLocales) {
if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0) { if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0) {
setLocale(it); setLocale(it);
break; return true;
} }
} }
return false;
} }
bool Configuration::windowColorIsDark() bool Configuration::windowColorIsDark()
@ -454,10 +464,23 @@ void Configuration::setConfig(const QString &key, const QVariant &value)
*/ */
QStringList Configuration::getAvailableTranslations() QStringList Configuration::getAvailableTranslations()
{ {
QDir dir(QCoreApplication::applicationDirPath() + QDir::separator() + const auto &trDirs = getTranslationsDirectories();
"translations");
QStringList fileNames = dir.entryList(QStringList("cutter_*.qm"), QDir::Files, QSet<QString> 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); QDir::Name);
for (const auto &trFile : currTrFileNames) {
fileNamesSet << trFile;
}
}
QStringList fileNames = fileNamesSet.toList();
qSort(fileNames);
QStringList languages; QStringList languages;
QString currLanguageName; QString currLanguageName;
auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, 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; 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
};
}

View File

@ -50,7 +50,7 @@ public:
// Languages // Languages
QLocale getCurrLocale() const; QLocale getCurrLocale() const;
void setLocale(const QLocale &l); void setLocale(const QLocale &l);
void setLocaleByName(const QString &language); bool setLocaleByName(const QString &language);
QStringList getAvailableTranslations(); QStringList getAvailableTranslations();
// Fonts // Fonts
@ -108,6 +108,11 @@ public:
void setConfig(const QString &key, const QVariant &value); void setConfig(const QString &key, const QVariant &value);
bool isFirstExecution(); bool isFirstExecution();
/*!
* \brief Get list of available translation directories (depends on configuration and OS)
* \return list of directories
*/
QStringList getTranslationsDirectories() const;
signals: signals:
void fontsUpdated(); void fontsUpdated();

View File

@ -16,6 +16,7 @@ WelcomeDialog::WelcomeDialog(QWidget *parent) :
ui(new Ui::WelcomeDialog) ui(new Ui::WelcomeDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
ui->logoSvgWidget->load(Config()->getLogoFile()); ui->logoSvgWidget->load(Config()->getLogoFile());
ui->versionLabel->setText("<font color='#a4a9b2'>" + tr("Version ") + CUTTER_VERSION_FULL + "</font>"); ui->versionLabel->setText("<font color='#a4a9b2'>" + tr("Version ") + CUTTER_VERSION_FULL + "</font>");
ui->themeComboBox->setCurrentIndex(Config()->getTheme()); ui->themeComboBox->setCurrentIndex(Config()->getTheme());

View File

@ -185,12 +185,12 @@ void AppearanceOptionsWidget::on_deleteButton_clicked()
void AppearanceOptionsWidget::onLanguageComboBoxCurrentIndexChanged(int index) void AppearanceOptionsWidget::onLanguageComboBoxCurrentIndexChanged(int index)
{ {
QString language = ui->languageComboBox->itemText(index).toLower(); 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; qWarning() << tr("Cannot set language, not found in available ones");
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();
} }

View File

@ -20,6 +20,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent)
{ {
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(this); ui->setupUi(this);
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
QList<PreferenceCategory> prefs { QList<PreferenceCategory> prefs {