1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

feat(Settings): Add system for versioning and upgrading Settings

Similar to how History handles SCHEMA_VERSION. Run separately on global and
personal settings, since some state in global, and personal settings can’t be
done globally since they require the passkey.

Restrict a user from downgrading past the saved settings version, due to
possible compatibility breaks or old qTox versions re-introducing corrupt state
that was already healed.

Pass in new profile state for personal settings rather than relying on settings
file presence because personal settings can be stored in either the personal
settings file or global settings file. This was introduced in
aea9eea8a4 when personal settings were first
moved to their own file.
This commit is contained in:
Anthony Bilinski 2022-03-03 12:36:09 -08:00
parent 7083a7d9bd
commit 2b41a06b55
No known key found for this signature in database
GPG Key ID: 2AA8E0DA1B31FB3C
56 changed files with 625 additions and 10 deletions

View File

@ -363,6 +363,10 @@ set(${PROJECT_NAME}_SOURCES
src/persistence/settings.h
src/persistence/settingsserializer.cpp
src/persistence/settingsserializer.h
src/persistence/globalsettingsupgrader.cpp
src/persistence/globalsettingsupgrader.h
src/persistence/personalsettingsupgrader.cpp
src/persistence/personalsettingsupgrader.h
src/persistence/smileypack.cpp
src/persistence/smileypack.h
src/persistence/toxsave.cpp

View File

@ -0,0 +1,57 @@
/*
Copyright © 2022 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre 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 3 of the License, or
(at your option) any later version.
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "globalsettingsupgrader.h"
#include <QDebug>
#include <cassert>
bool GlobalSettingsUpgrader::doUpgrade(Settings& settings, int fromVer, int toVer)
{
if (fromVer == toVer) {
return true;
}
if (fromVer > toVer) {
qWarning().nospace() << "Settings version (" << fromVer
<< ") is newer than we currently support (" << toVer
<< "). Please upgrade qTox";
return false;
}
using SettingsUpgradeFn = bool (*)(Settings&);
std::vector<SettingsUpgradeFn> upgradeFns = {};
assert(fromVer < static_cast<int>(upgradeFns.size()));
assert(toVer == static_cast<int>(upgradeFns.size()));
for (int i = fromVer; i < static_cast<int>(upgradeFns.size()); ++i) {
auto const newSettingsVersion = i + 1;
if (!upgradeFns[i](settings)) {
qCritical() << "Failed to upgrade settings to version " << newSettingsVersion << " aborting";
return false;
}
qDebug() << "Settings upgraded incrementally to schema version " << newSettingsVersion;
}
qInfo() << "Settings upgrade finished (settingsVersion" << fromVer << "->"
<< toVer << ")";
return true;
}

View File

@ -0,0 +1,27 @@
/*
Copyright © 2022 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre 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 3 of the License, or
(at your option) any later version.
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
class Settings;
namespace GlobalSettingsUpgrader
{
bool doUpgrade(Settings& settings, int fromVer, int toVer);
};

View File

@ -0,0 +1,57 @@
/*
Copyright © 2022 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre 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 3 of the License, or
(at your option) any later version.
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "personalsettingsupgrader.h"
#include <QDebug>
#include <cassert>
bool PersonalSettingsUpgrader::doUpgrade(SettingsSerializer& settingsSerializer, int fromVer, int toVer)
{
if (fromVer == toVer) {
return true;
}
if (fromVer > toVer) {
qWarning().nospace() << "Settings version (" << fromVer
<< ") is newer than we currently support (" << toVer
<< "). Please upgrade qTox";
return false;
}
using SettingsUpgradeFn = bool (*)(SettingsSerializer&);
std::vector<SettingsUpgradeFn> upgradeFns = {};
assert(fromVer < static_cast<int>(upgradeFns.size()));
assert(toVer == static_cast<int>(upgradeFns.size()));
for (int i = fromVer; i < static_cast<int>(upgradeFns.size()); ++i) {
auto const newSettingsVersion = i + 1;
if (!upgradeFns[i](settingsSerializer)) {
qCritical() << "Failed to upgrade settings to version " << newSettingsVersion << " aborting";
return false;
}
qDebug() << "Settings upgraded incrementally to schema version " << newSettingsVersion;
}
qInfo() << "Settings upgrade finished (settingsVersion" << fromVer << "->"
<< toVer << ")";
return true;
}

View File

@ -0,0 +1,27 @@
/*
Copyright © 2022 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre 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 3 of the License, or
(at your option) any later version.
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
class SettingsSerializer;
namespace PersonalSettingsUpgrader
{
bool doUpgrade(SettingsSerializer& settingsSerializer, int fromVer, int toVer);
};

View File

@ -336,9 +336,10 @@ Profile* Profile::loadProfile(const QString& name, const QString& password, Sett
Profile* p = new Profile(name, std::move(tmpKey), paths, settings);
// Core settings are saved per profile, need to load them before starting Core
settings.updateProfileData(p, parser);
constexpr bool isNewProfile = false;
settings.updateProfileData(p, parser, isNewProfile);
p->initCore(toxsave, settings, /*isNewProfile*/ false);
p->initCore(toxsave, settings, isNewProfile);
p->loadDatabase(password);
return p;
@ -366,9 +367,11 @@ Profile* Profile::createProfile(const QString& name, const QString& password, Se
settings.createPersonal(name);
Profile* p = new Profile(name, std::move(tmpKey), paths, settings);
settings.updateProfileData(p, parser);
p->initCore(QByteArray(), settings, /*isNewProfile*/ true);
constexpr bool isNewProfile = true;
settings.updateProfileData(p, parser, isNewProfile);
p->initCore(QByteArray(), settings, isNewProfile);
p->loadDatabase(password);
return p;
}

View File

@ -25,6 +25,8 @@
#include "src/persistence/profile.h"
#include "src/persistence/profilelocker.h"
#include "src/persistence/settingsserializer.h"
#include "src/persistence/globalsettingsupgrader.h"
#include "src/persistence/personalsettingsupgrader.h"
#include "src/persistence/smileypack.h"
#include "src/widget/gui.h"
#include "src/widget/style.h"
@ -39,6 +41,7 @@
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QErrorMessage>
#include <QFile>
#include <QFont>
#include <QList>
@ -61,6 +64,8 @@ const QString Settings::globalSettingsFile = "qtox.ini";
Settings* Settings::settings{nullptr};
CompatibleRecursiveMutex Settings::bigLock;
QThread* Settings::settingsThread{nullptr};
static constexpr int GLOBAL_SETTINGS_VERSION = 0;
static constexpr int PERSONAL_SETTINGS_VERSION = 0;
Settings::Settings()
: loaded(false)
@ -112,9 +117,11 @@ void Settings::loadGlobal()
QString filePath = dir.filePath(globalSettingsFile);
// If no settings file exist -- use the default one
bool defaultSettings = false;
if (!QFile(filePath).exists()) {
qDebug() << "No settings file found, using defaults";
filePath = ":/conf/" + globalSettingsFile;
defaultSettings = true;
}
qDebug() << "Loading settings from " + filePath;
@ -122,6 +129,22 @@ void Settings::loadGlobal()
QSettings s(filePath, QSettings::IniFormat);
s.setIniCodec("UTF-8");
s.beginGroup("Version");
{
const auto defaultVersion = defaultSettings ? GLOBAL_SETTINGS_VERSION : 0;
globalSettingsVersion = s.value("settingsVersion", defaultVersion).toInt();
}
s.endGroup();
auto upgradeSuccess = GlobalSettingsUpgrader::doUpgrade(*this, globalSettingsVersion, GLOBAL_SETTINGS_VERSION);
if (!upgradeSuccess) {
// Would be nice to show a GUI warning, but GUI isn't initialized yet.
// Trying to run without even default settings isn't sane.
std::terminate();
return;
}
globalSettingsVersion = GLOBAL_SETTINGS_VERSION;
s.beginGroup("Login");
{
autoLogin = s.value("autoLogin", false).toBool();
@ -259,7 +282,7 @@ void Settings::loadGlobal()
loaded = true;
}
void Settings::updateProfileData(Profile* profile, const QCommandLineParser* parser)
void Settings::updateProfileData(Profile* profile, const QCommandLineParser* parser, bool newProfile)
{
QMutexLocker locker{&bigLock};
@ -269,7 +292,7 @@ void Settings::updateProfileData(Profile* profile, const QCommandLineParser* par
}
setCurrentProfile(profile->getName());
saveGlobal();
loadPersonal(profile->getName(), profile->getPasskey());
loadPersonal(profile->getName(), profile->getPasskey(), newProfile);
if (parser) {
applyCommandLineOptions(*parser);
}
@ -458,7 +481,7 @@ bool Settings::applyCommandLineOptions(const QCommandLineParser& parser)
return true;
}
void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey, bool newProfile)
{
QMutexLocker locker{&bigLock};
@ -467,8 +490,9 @@ void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
// load from a profile specific friend data list if possible
QString tmp = dir.filePath(profileName + ".ini");
if (QFile(tmp).exists()) // otherwise, filePath remains the global file
if (QFile(tmp).exists()) { // otherwise, filePath remains the global file
filePath = tmp;
}
qDebug() << "Loading personal settings from" << filePath;
@ -476,6 +500,24 @@ void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
ps.load();
friendLst.clear();
ps.beginGroup("Version");
{
const auto defaultVersion = newProfile ? PERSONAL_SETTINGS_VERSION : 0;
personalSettingsVersion = ps.value("settingsVersion", defaultVersion).toInt();
}
ps.endGroup();
auto upgradeSuccess = PersonalSettingsUpgrader::doUpgrade(ps, personalSettingsVersion, PERSONAL_SETTINGS_VERSION);
if (!upgradeSuccess) {
GUI::showError(tr("Failed to load personal settings"),
tr("Unable to upgrade settings from version %1 to version %2. Cannot start qTox.")
.arg(personalSettingsVersion)
.arg(PERSONAL_SETTINGS_VERSION));
std::terminate();
return;
}
personalSettingsVersion = PERSONAL_SETTINGS_VERSION;
ps.beginGroup("Privacy");
{
typingNotification = ps.value("typingNotification", true).toBool();
@ -709,6 +751,12 @@ void Settings::saveGlobal()
s.setValue("screenGrabbed", screenGrabbed);
}
s.endGroup();
s.beginGroup("Version");
{
s.setValue("settingsVersion", globalSettingsVersion);
}
s.endGroup();
}
/**
@ -821,6 +869,12 @@ void Settings::savePersonal(QString profileName, const ToxEncrypt* passkey)
ps.setValue("blackList", blackList.join('\n'));
}
ps.endGroup();
ps.beginGroup("Version");
{
ps.setValue("settingsVersion", personalSettingsVersion);
}
ps.endGroup();
ps.save();
}

View File

@ -155,7 +155,7 @@ public:
void savePersonal();
void loadGlobal();
void loadPersonal(QString profileName, const ToxEncrypt* passKey);
void loadPersonal(QString profileName, const ToxEncrypt* passKey, bool newProfile);
void resetToDefault();
@ -170,7 +170,7 @@ public slots:
void saveGlobal();
void sync();
void setAutoLogin(bool state);
void updateProfileData(Profile* profile, const QCommandLineParser* parser);
void updateProfileData(Profile* profile, const QCommandLineParser* parser, bool newProfile);
signals:
// General
@ -717,4 +717,6 @@ private:
static const QString globalSettingsFile;
static QThread* settingsThread;
Paths paths;
int globalSettingsVersion = 0;
int personalSettingsVersion = 0;
};

8
translations/ar.ts vendored
View File

@ -2639,6 +2639,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>قائمة #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/be.ts vendored
View File

@ -2635,6 +2635,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Круг #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/bg.ts vendored
View File

@ -2636,6 +2636,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Кръг #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/cs.ts vendored
View File

@ -2639,6 +2639,14 @@ ID zahrnuje kód NoSpam (modře) a kontrolní součet (šedě).</translation>
<source>Circle #%1</source>
<translation>Kruh #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/da.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/de.ts vendored
View File

@ -2644,6 +2644,14 @@ Diese ID enthält den NoSpam-Code (in blau) und die Prüfsumme (in grau).</trans
<source>Circle #%1</source>
<translation>Kreis #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/el.ts vendored
View File

@ -2623,6 +2623,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Κύκλος #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/eo.ts vendored
View File

@ -2611,6 +2611,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Rondo #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/es.ts vendored
View File

@ -2636,6 +2636,14 @@ Este ID incluye el código NoSpam (en azul), y la suma de comprobación (en gris
<source>Circle #%1</source>
<translation>Círculo #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/et.ts vendored
View File

@ -2638,6 +2638,14 @@ See ID sisaldab NoSpam koodi (sinine) ja kontrollsumma (hall).</translation>
<source>Circle #%1</source>
<translation>Suhtlusring #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/fa.ts vendored
View File

@ -2627,6 +2627,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>حلقه #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/fi.ts vendored
View File

@ -2635,6 +2635,14 @@ Tämä ID sisältää spammin estävän koodin(joka on sinisellä), ja tarkistus
<source>Circle #%1</source>
<translation>Piiri #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/fr.ts vendored
View File

@ -2635,6 +2635,14 @@ Cet identifiant comprend le code NoSpam (en bleu) et la somme de contrôle (en g
<source>Circle #%1</source>
<translation>Cercle nᵒ%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/gl.ts vendored
View File

@ -2631,6 +2631,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Círculo #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/he.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/hr.ts vendored
View File

@ -2627,6 +2627,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Kružok #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/hu.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>#%1. kör</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/is.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/it.ts vendored
View File

@ -2632,6 +2632,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Circolo #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ja.ts vendored
View File

@ -2618,6 +2618,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>サークル #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/kn.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ko.ts vendored
View File

@ -2617,6 +2617,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/lt.ts vendored
View File

@ -2641,6 +2641,14 @@ Pasidalinkite ja su draugais, kad pradėtumėte kalbėtis.
<source>Circle #%1</source>
<translation>Draugų ratas Nr. %1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/lv.ts vendored
View File

@ -2642,6 +2642,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Uz sarakstu #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/mk.ts vendored
View File

@ -2635,6 +2635,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Круг #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/nl.ts vendored
View File

@ -2623,6 +2623,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Cirkel #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

View File

@ -2631,6 +2631,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Cirkel #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

View File

@ -2625,6 +2625,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Sirkel #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/pl.ts vendored
View File

@ -2661,6 +2661,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Krąg #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/pt.ts vendored
View File

@ -2635,6 +2635,14 @@ Este ID inclui o código NoSpam (em azul) e o checkum (em cinzento).</translatio
<source>Circle #%1</source>
<translation>Círculo #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

View File

@ -2643,6 +2643,14 @@ Este ID inclui o código NoSpam (em azul) e o checkum (em cinza).</translation>
<source>Circle #%1</source>
<translation>Círculo #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ro.ts vendored
View File

@ -2647,6 +2647,14 @@ Acest ID include codul NoSpam (în albastru) și suma de control (în gri).</tra
<source>Circle #%1</source>
<translation>Cerc #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ru.ts vendored
View File

@ -2645,6 +2645,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Список #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/si.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/sk.ts vendored
View File

@ -2647,6 +2647,14 @@ Toto ID obsahuje kód NoSpam (modrou) a kontrolný súčet (šedou).</translatio
<source>Circle #%1</source>
<translation>Kruh #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/sl.ts vendored
View File

@ -2629,6 +2629,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/sq.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/sr.ts vendored
View File

@ -2635,6 +2635,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Круг #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

View File

@ -2636,6 +2636,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>Krug #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/sv.ts vendored
View File

@ -2635,6 +2635,14 @@ ID:t innehåller NoSpam-koden (i blått) och kontrollsumman (i grått).</transla
<source>Circle #%1</source>
<translation>Cirkel #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/sw.ts vendored
View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ta.ts vendored
View File

@ -2625,6 +2625,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/tr.ts vendored
View File

@ -2635,6 +2635,14 @@ Bu kimlik NoSpam kodunu (mavi) ve sağlama toplamını (gri) içerir.</translati
<source>Circle #%1</source>
<translation>Çevre #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ug.ts vendored
View File

@ -2631,6 +2631,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>چەمبىرەك #%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/uk.ts vendored
View File

@ -2635,6 +2635,14 @@ It&apos;s difficult to translate &quot;Tox me maybe&quot; because in Ukrainian n
<source>Circle #%1</source>
<translation>Коло №%1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

8
translations/ur.ts vendored
View File

@ -2627,6 +2627,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

View File

@ -2631,6 +2631,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation>圈子 # %1</translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>

View File

@ -2619,6 +2619,14 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
<source>Circle #%1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to load personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to upgrade settings from version %1 to version %2. Cannot start qTox.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>