summaryrefslogtreecommitdiffstats
path: root/Plugins/ScriptingPython
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2023-04-30 18:30:36 -0400
committerLibravatarUnit 193 <unit193@unit193.net>2023-04-30 18:30:36 -0400
commit3565aad630864ecdbe53fdaa501ea708555b3c7c (patch)
treec743e4ad0bad39ebdb2f514c7cc52d34a257ebbe /Plugins/ScriptingPython
parent1fdc150116cad39aae5c5da407c3312b47a59e3a (diff)
New upstream version 3.4.4+dfsg.upstream/3.4.4+dfsg
Diffstat (limited to 'Plugins/ScriptingPython')
-rw-r--r--Plugins/ScriptingPython/ScriptingPython.pro34
-rw-r--r--Plugins/ScriptingPython/icon_attribution.txt1
-rw-r--r--Plugins/ScriptingPython/scriptingpython.cpp666
-rw-r--r--Plugins/ScriptingPython/scriptingpython.h96
-rw-r--r--Plugins/ScriptingPython/scriptingpython.json8
-rw-r--r--Plugins/ScriptingPython/scriptingpython.pngbin0 -> 559 bytes
-rw-r--r--Plugins/ScriptingPython/scriptingpython.qrc5
-rw-r--r--Plugins/ScriptingPython/scriptingpython_global.h12
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_af_ZA.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_ar_SA.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_ca_ES.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_cs_CZ.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_da_DK.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_de_DE.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_el_GR.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_en_US.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_es_ES.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_fa_IR.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_fi_FI.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_fr_FR.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_he_IL.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_hu_HU.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_it_IT.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_ja_JP.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_kaa.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_ko_KR.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_nl_NL.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_no_NO.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_pl_PL.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_pt_BR.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_pt_PT.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_ro_RO.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_ru_RU.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_sk_SK.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_sr_SP.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_sv_SE.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_tr_TR.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_uk_UA.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_vi_VN.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_zh_CN.ts32
-rw-r--r--Plugins/ScriptingPython/translations/ScriptingPython_zh_TW.ts32
42 files changed, 1910 insertions, 0 deletions
diff --git a/Plugins/ScriptingPython/ScriptingPython.pro b/Plugins/ScriptingPython/ScriptingPython.pro
new file mode 100644
index 0000000..02fb5d3
--- /dev/null
+++ b/Plugins/ScriptingPython/ScriptingPython.pro
@@ -0,0 +1,34 @@
+QT -= gui
+
+include($$PWD/../../SQLiteStudio3/plugins.pri)
+
+TARGET = ScriptingPython
+TEMPLATE = lib
+
+DEFINES += SCRIPTINGPYTHON_LIBRARY
+
+QMAKE_CXXFLAGS += -Wno-cast-function-type
+
+SOURCES += scriptingpython.cpp
+
+HEADERS += scriptingpython.h\
+ scriptingpython_global.h
+
+OTHER_FILES += \
+ scriptingpython.json
+
+linux: {
+ LIBS += -lpython3.9
+}
+
+macx: {
+ LIBS += -lpython3.9
+}
+
+win32: {
+ INCLUDEPATH += $$PWD/../../../include/python
+ LIBS += -lpython39 -L$$PWD/../../../lib/python
+}
+
+RESOURCES += \
+ scriptingpython.qrc
diff --git a/Plugins/ScriptingPython/icon_attribution.txt b/Plugins/ScriptingPython/icon_attribution.txt
new file mode 100644
index 0000000..8211625
--- /dev/null
+++ b/Plugins/ScriptingPython/icon_attribution.txt
@@ -0,0 +1 @@
+Python icon was made by Freepik - https://www.freepik.com
diff --git a/Plugins/ScriptingPython/scriptingpython.cpp b/Plugins/ScriptingPython/scriptingpython.cpp
new file mode 100644
index 0000000..1dedb5c
--- /dev/null
+++ b/Plugins/ScriptingPython/scriptingpython.cpp
@@ -0,0 +1,666 @@
+#include "scriptingpython.h"
+#include "common/global.h"
+#include "common/unused.h"
+#include "db/db.h"
+#include "db/sqlite3.h"
+#include "parser/lexer.h"
+#include "parser/token.h"
+#include "common/utils_sql.h"
+#include <QDebug>
+#include <QMutexLocker>
+#include <frameobject.h>
+
+static PyMethodDef pyDbMethods[] = {
+ {"eval", reinterpret_cast<PyCFunction>(ScriptingPython::dbEval), METH_FASTCALL, ""},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static PyModuleDef pyDbModule = {
+ PyModuleDef_HEAD_INIT, "db", nullptr, -1, pyDbMethods,
+ nullptr, nullptr, nullptr, nullptr
+};
+
+static PyObject* pyDbModuleInit(void)
+{
+ return PyModule_Create(&pyDbModule);
+}
+
+QHash<PyThreadState*, ScriptingPython::ContextPython*> ScriptingPython::contexts;
+
+ScriptingPython::ScriptingPython()
+{
+ mainInterpMutex = new QMutex();
+}
+
+ScriptingPython::~ScriptingPython()
+{
+ safe_delete(mainInterpMutex);
+}
+
+bool ScriptingPython::init()
+{
+ SQLS_INIT_RESOURCE(scriptingpython);
+ QMutexLocker locker(mainInterpMutex);
+
+ PyImport_AppendInittab("db", &pyDbModuleInit);
+ Py_Initialize();
+ PyRun_SimpleString("import db");
+
+ mainContext = new ContextPython();
+ contexts[mainContext->interp] = mainContext;
+ return true;
+}
+
+void ScriptingPython::deinit()
+{
+ QMutexLocker locker(mainInterpMutex);
+ contexts.clear();
+ Py_Finalize();
+ SQLS_CLEANUP_RESOURCE(scriptingpython);
+}
+
+QString ScriptingPython::getLanguage() const
+{
+ return "Python";
+}
+
+ScriptingPlugin::Context* ScriptingPython::createContext()
+{
+ ContextPython* ctx = new ContextPython();
+ contexts[ctx->interp] = ctx;
+ return ctx;
+}
+
+void ScriptingPython::releaseContext(ScriptingPlugin::Context* context)
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return;
+
+ contexts.remove(ctx->interp);
+ delete ctx;
+ PyThreadState_Swap(mainContext->interp);
+}
+
+void ScriptingPython::resetContext(ScriptingPlugin::Context* context)
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return;
+
+ ctx->reset();
+}
+
+void ScriptingPython::setVariable(ScriptingPlugin::Context* context, const QString& name, const QVariant& value)
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return;
+
+ PyObject* obj = variantToPythonObj(value);
+ PyDict_SetItemString(ctx->envDict, name.toUtf8().constData(), obj);
+ Py_DECREF(obj);
+}
+
+
+QVariant ScriptingPython::getVariable(ScriptingPlugin::Context* context, const QString& name)
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return QVariant();
+
+ PyThreadState_Swap(ctx->interp);
+ return getVariable(name);
+}
+
+bool ScriptingPython::hasError(ScriptingPlugin::Context* context) const
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return false;
+
+ return !ctx->error.isEmpty();
+}
+
+QString ScriptingPython::getErrorMessage(ScriptingPlugin::Context* context) const
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return QString();
+
+ return ctx->error;
+}
+
+QString ScriptingPython::getIconPath() const
+{
+ return ":/scriptingpython/scriptingpython.png";
+}
+
+QVariant ScriptingPython::evaluate(ScriptingPlugin::Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking)
+{
+ ContextPython* ctx = getContext(context);
+ if (!ctx)
+ return QVariant();
+
+ return compileAndEval(ctx, code, funcInfo, args, db, locking);
+}
+
+QVariant ScriptingPython::evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage)
+{
+ QMutexLocker locker(mainInterpMutex);
+ QVariant results = compileAndEval(mainContext, code, funcInfo, args, db, locking);
+
+ if (errorMessage && !mainContext->error.isEmpty())
+ *errorMessage = mainContext->error;
+
+ return results;
+}
+
+ScriptingPython::ContextPython* ScriptingPython::getContext(ScriptingPlugin::Context* context) const
+{
+ ContextPython* ctx = dynamic_cast<ContextPython*>(context);
+ if (!ctx)
+ qDebug() << "Invalid context passed to ScriptingPython:" << context;
+
+ return ctx;
+}
+
+QVariant ScriptingPython::compileAndEval(ScriptingPython::ContextPython* ctx, const QString& code, const FunctionInfo& funcInfo,
+ const QList<QVariant>& args, Db* db, bool locking)
+{
+ PyThreadState_Swap(ctx->interp);
+ clearError(ctx);
+
+ ScriptObject* scriptObj = getScriptObject(code, funcInfo, ctx);
+ if (PyErr_Occurred() || !scriptObj->getCompiled())
+ {
+ ctx->error = extractError();
+ return QVariant();
+ }
+
+ ctx->db = db;
+ ctx->useDbLocking = locking;
+
+ PyObject* pyArgs = argsToPyArgs(args, funcInfo.getArguments());
+ PyObject* result = PyObject_CallObject(scriptObj->getCompiled(), pyArgs);
+ Py_DECREF(pyArgs);
+
+ ctx->db = nullptr;
+ ctx->useDbLocking = false;
+
+ if (PyErr_Occurred())
+ {
+ Py_XDECREF(result);
+ ctx->error = extractError();
+ return QVariant();
+ }
+
+ QVariant resultVariant = pythonObjToVariant(result);
+ Py_XDECREF(result);
+ return resultVariant;
+}
+
+QString ScriptingPython::extractError()
+{
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+ if (!value)
+ return QString();
+
+ PyObject* strErr = PyObject_Repr(value);
+ QString err = QString::fromUtf8(PyUnicode_AsUTF8(strErr));
+ PyErr_Clear();
+
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(traceback);
+ Py_XDECREF(strErr);
+
+ return err;
+}
+
+void ScriptingPython::clearError(ContextPython* ctx)
+{
+ PyErr_Clear();
+ ctx->error.clear();
+}
+
+ScriptingPython::ScriptObject* ScriptingPython::getScriptObject(const QString code, const ScriptingPlugin::FunctionInfo& funcInfo, ContextPython* ctx)
+{
+ static const QString keyTpl = QStringLiteral("{%1} %2");
+
+ QString key = keyTpl.arg(funcInfo.getArguments().join("#"), code);
+ if (ctx->scriptCache.contains(key))
+ return ctx->scriptCache[key];
+
+ ScriptObject* scriptObj = new ScriptObject(code, funcInfo, ctx);
+ ctx->scriptCache.insert(key, scriptObj);
+ return scriptObj;
+}
+
+PyObject* ScriptingPython::argsToPyArgs(const QVariantList& args, const QStringList& namedParameters)
+{
+ PyObject* result = PyTuple_New(args.size());
+ PyObject* namedParamTuple = namedParameters.isEmpty() ? nullptr : PyTuple_New(namedParameters.size() + 1);
+ int i = 0;
+ for (const QVariant& value : args)
+ {
+ PyObject* valueObj = variantToPythonObj(value);
+ PyTuple_SetItem(result, i, valueObj);
+ if (namedParamTuple && i < namedParameters.size())
+ {
+ Py_INCREF(valueObj);
+ PyTuple_SetItem(namedParamTuple, i, valueObj);
+ }
+ i++;
+ }
+
+ // If function has named parameters, than named param tuple takes precedense
+ // and positional tuple becomes last argument.
+ if (namedParamTuple)
+ {
+ PyTuple_SetItem(namedParamTuple, namedParameters.size(), result);
+ result = namedParamTuple;
+ }
+
+ return result;
+}
+
+QVariant ScriptingPython::pythonObjToVariant(PyObject* obj)
+{
+ if (!obj)
+ return QVariant();
+
+ if (PyUnicode_Check(obj))
+ return QString::fromUtf8(PyUnicode_AsUTF8(obj));
+
+ if (PyLong_Check(obj))
+ return PyLong_AsLongLong(obj);
+
+ if (PyBool_Check(obj))
+ return PyObject_IsTrue(obj) != 0;
+
+ if (PyFloat_Check(obj))
+ return PyFloat_AsDouble(obj);
+
+ if (PyBytes_Check(obj))
+ {
+ char* buf;
+ Py_ssize_t size;
+ if (PyBytes_AsStringAndSize(obj, &buf, &size) != 0)
+ return QVariant();
+
+ return QByteArray::fromRawData(buf, size);
+ }
+
+ if (PyByteArray_Check(obj))
+ {
+ char* buf = PyByteArray_AsString(obj);
+ Py_ssize_t size = PyByteArray_Size(obj);
+ return QByteArray::fromRawData(buf, size);
+ }
+
+ if (PyTuple_Check(obj))
+ {
+ QList<QVariant> result;
+
+ Py_ssize_t size = PyTuple_Size(obj);
+ for (Py_ssize_t i = 0; i < size; i++)
+ result << pythonObjToVariant(PyTuple_GetItem(obj, i));
+
+ return result;
+ }
+
+ if (PyList_Check(obj))
+ {
+ QList<QVariant> result;
+
+ Py_ssize_t size = PyList_Size(obj);
+ for (Py_ssize_t i = 0; i < size; i++)
+ result << pythonObjToVariant(PyList_GetItem(obj, i));
+
+ return result;
+ }
+
+ if (PySet_Check(obj))
+ {
+ QSet<QVariant> result;
+
+ PyObject *iterator = PyObject_GetIter(obj);
+ PyObject *item;
+
+ if (iterator == NULL)
+ return QVariant();
+
+ while ((item = PyIter_Next(iterator)))
+ {
+ result << pythonObjToVariant(item);
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iterator);
+
+ return QVariant::fromValue(result);
+ }
+
+ if (PyDict_Check(obj))
+ {
+ QHash<QString, QVariant> result;
+
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(obj, &pos, &key, &value))
+ result[pythonObjToString(key)] = pythonObjToVariant(value);
+
+ return result;
+ }
+
+ PyObject* strObj = PyObject_Repr(obj);
+ QString result = QString::fromUtf8(PyUnicode_AsUTF8(strObj));
+ Py_DECREF(strObj);
+ return result;
+}
+
+QString ScriptingPython::pythonObjToString(PyObject* obj)
+{
+ PyObject* strObj = PyObject_Repr(obj);
+ if (!strObj)
+ return QString();
+
+ QString result = QString::fromUtf8(PyUnicode_AsUTF8(strObj));
+ Py_DECREF(strObj);
+ return result;
+}
+
+PyObject* ScriptingPython::variantToPythonObj(const QVariant& value)
+{
+ PyObject* obj = nullptr;
+ switch (value.type())
+ {
+ case QVariant::Bool:
+ obj = PyBool_FromLong(value.toBool() ? 1L : 0L);
+ break;
+ case QVariant::Int:
+ case QVariant::LongLong:
+ obj = PyLong_FromLongLong(value.toLongLong());
+ break;
+ case QVariant::UInt:
+ case QVariant::ULongLong:
+ obj = PyLong_FromUnsignedLongLong(value.toULongLong());
+ break;
+ case QVariant::Double:
+ obj = PyFloat_FromDouble(value.toDouble());
+ break;
+ case QVariant::ByteArray:
+ {
+ QByteArray bytes = value.toByteArray();
+ char* data = bytes.data();
+ obj = PyBytes_FromStringAndSize(data, bytes.size());
+ break;
+ }
+ case QVariant::List:
+ {
+ QList<QVariant> list = value.toList();
+ int listSize = list.size();
+ obj = PyList_New(listSize);
+ int pos = 0;
+ for (const QVariant& item : list)
+ {
+ PyObject* subObj = variantToPythonObj(item);
+ PyList_SetItem(obj, pos++, subObj);
+ Py_DECREF(subObj);
+ }
+
+ break;
+ }
+ case QVariant::StringList:
+ {
+ QStringList list = value.toStringList();
+ int listSize = list.size();
+ obj = PyList_New(listSize);
+ int pos = 0;
+ for (const QVariant& item : list)
+ {
+ PyObject* subObj = variantToPythonObj(item);
+ PyList_SetItem(obj, pos++, subObj);
+ Py_DECREF(subObj);
+ }
+
+ break;
+ }
+ case QVariant::Hash:
+ {
+ QHash<QString, QVariant> hash = value.toHash();
+ obj = PyDict_New();
+ QHashIterator<QString, QVariant> it(hash);
+ while (it.hasNext())
+ {
+ it.next();
+ PyObject* subObj = variantToPythonObj(it.value());
+ PyDict_SetItemString(obj, it.key().toUtf8().constData(), subObj);
+ Py_DECREF(subObj);
+ }
+ break;
+ }
+ case QVariant::Map:
+ {
+ QMap<QString, QVariant> map = value.toMap();
+ obj = PyDict_New();
+ QMapIterator<QString, QVariant> it(map);
+ while (it.hasNext())
+ {
+ it.next();
+ PyObject* subObj = variantToPythonObj(it.value());
+ PyDict_SetItemString(obj, it.key().toUtf8().constData(), subObj);
+ Py_DECREF(subObj);
+ }
+ break;
+ }
+ case QVariant::String:
+ default:
+ obj = stringToPythonObj(value.toString());
+ break;
+ }
+
+ if (!obj)
+ obj = stringToPythonObj(value.toString());
+
+ return obj;
+}
+
+PyObject* ScriptingPython::stringToPythonObj(const QString& value)
+{
+ QByteArray bytes = value.toUtf8();
+ return PyUnicode_FromStringAndSize(bytes.constData(), bytes.size());
+}
+
+PyObject* ScriptingPython::dbEval(PyObject* self, PyObject *const *args, Py_ssize_t nargs)
+{
+ UNUSED(self);
+
+ if (nargs != 1)
+ {
+ PyErr_SetString(PyExc_RuntimeError, QObject::tr("Invalid use of %1 function. Expected %2 arguments, but got %3.")
+ .arg("db.eval()", QString::number(1), QString::number(nargs))
+ .toUtf8().constData());
+ return nullptr;
+ }
+
+ SqlQueryPtr execResults = dbCommonEval(args[0], "db.eval()");
+ if (!execResults)
+ {
+ PyErr_SetString(PyExc_RuntimeError, QObject::tr("Unknown error from function %1.").arg("db.eval()").toUtf8().constData());
+ return nullptr;
+ }
+
+ if (execResults->isError())
+ {
+ PyErr_SetString(PyExc_RuntimeError, execResults->getErrorText().toUtf8().constData());
+ return nullptr;
+ }
+
+ QList<PyObject*> tuples;
+ while (execResults->hasNext())
+ {
+ SqlResultsRowPtr row = execResults->next();
+ PyObject* tuple = PyTuple_New(row->valueList().size());
+ int pos = 0;
+ for (const QVariant& cell : row->valueList())
+ PyTuple_SetItem(tuple, pos++, variantToPythonObj(cell));
+
+ tuples << tuple;
+ }
+
+ PyObject* resultObject = PyList_New(0);
+ for (PyObject* tuple : tuples)
+ {
+ PyList_Append(resultObject, tuple);
+ Py_DECREF(tuple);
+ }
+
+ return resultObject;
+}
+
+SqlQueryPtr ScriptingPython::dbCommonEval(PyObject* sqlArg, const char* fnName)
+{
+ QString sql;
+ if (!PyUnicode_Check(sqlArg))
+ {
+ PyObject* strObj = PyObject_Repr(sqlArg);
+ if (!strObj)
+ {
+ return SqlQuery::error(
+ QObject::tr("Could not calculate string representation of the Python object passed as argument to the function %1.")
+ .arg(fnName),
+ SQLITE_ERROR);
+ }
+
+ sql = QString::fromUtf8(PyUnicode_AsUTF8(strObj));
+ Py_DECREF(strObj);
+ }
+ else
+ sql = QString::fromUtf8(PyUnicode_AsUTF8(sqlArg));
+
+ PyThreadState* state = PyThreadState_Get();
+ ContextPython* ctx = contexts[state];
+ if (!ctx)
+ {
+ return SqlQuery::error(
+ QObject::tr("Could not find execution context for function %1. This is a bug of Python plugin. Please report it.")
+ .arg(fnName),
+ SQLITE_ERROR);
+ }
+
+ Db::Flags flags;
+ if (!ctx->useDbLocking)
+ flags |= Db::Flag::NO_LOCK;
+
+ TokenList bindTokens = Lexer::tokenize(sql).filter(Token::BIND_PARAM);
+ QString bindVarName;
+ QHash<QString, QVariant> queryArgs;
+ for (const TokenPtr& token : bindTokens)
+ {
+ bindVarName = getBindTokenName(token);
+ if (bindVarName == "?")
+ continue;
+
+ queryArgs[token->value] = getVariable(bindVarName);
+ }
+
+ SqlQueryPtr execResults = ctx->db->exec(sql, queryArgs, flags);
+ if (execResults->isError())
+ {
+ return SqlQuery::error(
+ QObject::tr("Error from Python function %1: %2")
+ .arg(fnName, execResults->getErrorText()),
+ SQLITE_ERROR);
+ }
+ return execResults;
+}
+
+QVariant ScriptingPython::getVariable(const QString& name)
+{
+ PyThreadState* state = PyThreadState_Get();
+ if (!state->frame)
+ return QVariant();
+
+ const char* varName = name.toUtf8().constData();
+ PyObject* obj = nullptr;
+
+ PyFrame_FastToLocals(state->frame);
+ PyObject* locals = state->frame->f_locals;
+ PyObject* globals = state->frame->f_globals;
+ if (PyMapping_Check(locals))
+ obj = PyMapping_GetItemString(locals, varName);
+ else if (PyDict_Check(globals))
+ obj = PyDict_GetItemString(globals, varName);
+
+ if (!obj)
+ return QVariant();
+
+ return pythonObjToVariant(obj);
+}
+
+ScriptingPython::ScriptObject::ScriptObject(const QString& code, const ScriptingPlugin::FunctionInfo& funcInfo, ContextPython* context)
+{
+ static_qstring(fnTpl, "def fn(%1%2*args):\n%3");
+
+ QString indentedCode = indentMultiline(code);
+ QByteArray utf8Bytes = funcInfo.getUndefinedArgs() ?
+ fnTpl.arg("", "", indentedCode).toUtf8() :
+ fnTpl.arg(funcInfo.getArguments().join(", "), ", ", indentedCode).toUtf8();
+
+ PyObject* result = PyRun_String(utf8Bytes.constData(), Py_file_input, context->envDict, context->envDict);
+ if (!result)
+ return;
+
+ Py_DECREF(result);
+ compiled = PyObject_GetAttrString(context->mainModule, "fn");
+}
+
+ScriptingPython::ScriptObject::~ScriptObject()
+{
+ Py_CLEAR(compiled);
+}
+
+PyObject* ScriptingPython::ScriptObject::getCompiled() const
+{
+ return compiled;
+}
+
+ScriptingPython::ContextPython::ContextPython()
+{
+ scriptCache.setMaxCost(cacheSize);
+ init();
+}
+
+ScriptingPython::ContextPython::~ContextPython()
+{
+ clear();
+}
+
+void ScriptingPython::ContextPython::reset()
+{
+ clear();
+ init();
+}
+
+void ScriptingPython::ContextPython::init()
+{
+ interp = Py_NewInterpreter();
+ PyThreadState_Swap(interp);
+ mainModule = PyImport_AddModule("__main__");
+ envDict = PyModule_GetDict(mainModule);
+ PyRun_SimpleString("import db");
+}
+
+void ScriptingPython::ContextPython::clear()
+{
+ PyThreadState_Swap(interp);
+ PyDict_Clear(envDict);
+ scriptCache.clear();
+ PyErr_Clear();
+ Py_EndInterpreter(interp);
+ error = QString();
+}
diff --git a/Plugins/ScriptingPython/scriptingpython.h b/Plugins/ScriptingPython/scriptingpython.h
new file mode 100644
index 0000000..ef88a20
--- /dev/null
+++ b/Plugins/ScriptingPython/scriptingpython.h
@@ -0,0 +1,96 @@
+#ifndef SCRIPTINGPYTHON_H
+#define SCRIPTINGPYTHON_H
+
+#include <Python.h>
+
+#include "scriptingpython_global.h"
+#include "plugins/genericplugin.h"
+#include "plugins/scriptingplugin.h"
+#include "db/sqlquery.h"
+#include <QCache>
+
+class QMutex;
+
+class SCRIPTINGPYTHONSHARED_EXPORT ScriptingPython : public GenericPlugin, public DbAwareScriptingPlugin
+{
+ Q_OBJECT
+ SQLITESTUDIO_PLUGIN("scriptingpython.json")
+
+ public:
+ static PyObject* dbEval(PyObject *self, PyObject* const* args, Py_ssize_t nargs);
+
+ ScriptingPython();
+ ~ScriptingPython();
+
+ bool init();
+ void deinit();
+ QString getLanguage() const;
+ Context* createContext();
+ void releaseContext(Context* context);
+ void resetContext(Context* context);
+ void setVariable(Context* context, const QString& name, const QVariant& value);
+ QVariant getVariable(Context* context, const QString& name);
+ bool hasError(Context* context) const;
+ QString getErrorMessage(Context* context) const;
+ QString getIconPath() const;
+ QVariant evaluate(Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking = false);
+ QVariant evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking = false, QString* errorMessage = nullptr);
+
+ private:
+ class ContextPython;
+ class ScriptObject
+ {
+ public:
+ ScriptObject(const QString& code, const FunctionInfo& funcInfo, ContextPython* context);
+ ~ScriptObject();
+
+ PyObject* getCompiled() const;
+
+ private:
+ PyObject* compiled = nullptr;
+ };
+
+ class ContextPython : public ScriptingPlugin::Context
+ {
+ public:
+ ContextPython();
+ ~ContextPython();
+
+ void reset();
+
+ PyThreadState* interp = nullptr;
+ PyObject* mainModule = nullptr;
+ PyObject* envDict = nullptr;
+ QCache<QString, ScriptObject> scriptCache;
+ QString error;
+ Db* db = nullptr;
+ bool useDbLocking = false;
+
+ private:
+ void init();
+ void clear();
+ };
+
+ ContextPython* getContext(ScriptingPlugin::Context* context) const;
+ QVariant compileAndEval(ContextPython* ctx, const QString& code, const FunctionInfo& funcInfo,
+ const QList<QVariant>& args, Db* db, bool locking);
+ void clearError(ContextPython* ctx);
+ ScriptObject* getScriptObject(const QString code, const ScriptingPlugin::FunctionInfo& funcInfo, ContextPython* ctx);
+
+ static QString extractError();
+ static PyObject* argsToPyArgs(const QVariantList& args, const QStringList& namedParameters);
+ static QVariant pythonObjToVariant(PyObject* obj);
+ static QString pythonObjToString(PyObject* obj);
+ static PyObject* variantToPythonObj(const QVariant& value);
+ static PyObject* stringToPythonObj(const QString& value);
+ static SqlQueryPtr dbCommonEval(PyObject* sqlArg, const char* fnName);
+ static QVariant getVariable(const QString& name);
+
+ static const constexpr int cacheSize = 5;
+ static QHash<PyThreadState*, ContextPython*> contexts;
+
+ ContextPython* mainContext = nullptr;
+ QMutex* mainInterpMutex = nullptr;
+};
+
+#endif // SCRIPTINGPYTHON_H
diff --git a/Plugins/ScriptingPython/scriptingpython.json b/Plugins/ScriptingPython/scriptingpython.json
new file mode 100644
index 0000000..c7c67bd
--- /dev/null
+++ b/Plugins/ScriptingPython/scriptingpython.json
@@ -0,0 +1,8 @@
+{
+ "type": "ScriptingPlugin",
+ "title": "Python scripting",
+ "description": "Provides Python scripting language support for SQLiteStudio.",
+ "version": 10000,
+ "author": "SalSoft",
+ "loadByDefault": false
+}
diff --git a/Plugins/ScriptingPython/scriptingpython.png b/Plugins/ScriptingPython/scriptingpython.png
new file mode 100644
index 0000000..fb510e4
--- /dev/null
+++ b/Plugins/ScriptingPython/scriptingpython.png
Binary files differ
diff --git a/Plugins/ScriptingPython/scriptingpython.qrc b/Plugins/ScriptingPython/scriptingpython.qrc
new file mode 100644
index 0000000..24ae6da
--- /dev/null
+++ b/Plugins/ScriptingPython/scriptingpython.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/scriptingpython">
+ <file>scriptingpython.png</file>
+ </qresource>
+</RCC>
diff --git a/Plugins/ScriptingPython/scriptingpython_global.h b/Plugins/ScriptingPython/scriptingpython_global.h
new file mode 100644
index 0000000..63c42e0
--- /dev/null
+++ b/Plugins/ScriptingPython/scriptingpython_global.h
@@ -0,0 +1,12 @@
+#ifndef SCRIPTINGPYTHON_GLOBAL_H
+#define SCRIPTINGPYTHON_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(SCRIPTINGPYTHON_LIBRARY)
+# define SCRIPTINGPYTHONSHARED_EXPORT Q_DECL_EXPORT
+#else
+# define SCRIPTINGPYTHONSHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // SCRIPTINGPYTHON_GLOBAL_H
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython.ts b/Plugins/ScriptingPython/translations/ScriptingPython.ts
new file mode 100644
index 0000000..7d4c86c
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_af_ZA.ts b/Plugins/ScriptingPython/translations/ScriptingPython_af_ZA.ts
new file mode 100644
index 0000000..ddd0cf0
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_af_ZA.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="af" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_ar_SA.ts b/Plugins/ScriptingPython/translations/ScriptingPython_ar_SA.ts
new file mode 100644
index 0000000..bd7a411
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_ar_SA.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ar" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_ca_ES.ts b/Plugins/ScriptingPython/translations/ScriptingPython_ca_ES.ts
new file mode 100644
index 0000000..2beab4f
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_ca_ES.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ca" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_cs_CZ.ts b/Plugins/ScriptingPython/translations/ScriptingPython_cs_CZ.ts
new file mode 100644
index 0000000..a840976
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_cs_CZ.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="cs" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_da_DK.ts b/Plugins/ScriptingPython/translations/ScriptingPython_da_DK.ts
new file mode 100644
index 0000000..63d5776
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_da_DK.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="da" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_de_DE.ts b/Plugins/ScriptingPython/translations/ScriptingPython_de_DE.ts
new file mode 100644
index 0000000..5798d98
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_de_DE.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_el_GR.ts b/Plugins/ScriptingPython/translations/ScriptingPython_el_GR.ts
new file mode 100644
index 0000000..369d7a2
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_el_GR.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="el" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_en_US.ts b/Plugins/ScriptingPython/translations/ScriptingPython_en_US.ts
new file mode 100644
index 0000000..ebb0fbd
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_en_US.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="en" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_es_ES.ts b/Plugins/ScriptingPython/translations/ScriptingPython_es_ES.ts
new file mode 100644
index 0000000..26d0df2
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_es_ES.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="es-ES" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_fa_IR.ts b/Plugins/ScriptingPython/translations/ScriptingPython_fa_IR.ts
new file mode 100644
index 0000000..0cb1654
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_fa_IR.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fa" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_fi_FI.ts b/Plugins/ScriptingPython/translations/ScriptingPython_fi_FI.ts
new file mode 100644
index 0000000..c8a3691
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_fi_FI.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fi" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_fr_FR.ts b/Plugins/ScriptingPython/translations/ScriptingPython_fr_FR.ts
new file mode 100644
index 0000000..2bf1d89
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_fr_FR.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>Utilisation non valide de la fonction %1. Attendait %2 arguments, mais a obtenu %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>Erreur inconnue de la fonction %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>Impossible de calculer la représentation de la chaîne de caractères de l&apos;objet Python passé comme argument à la fonction %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>Impossible de trouver le contexte d&apos;exécution de la fonction %1. Ceci est un bug du plugin Python. Veuillez le signaler.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Erreur de la fonction Python %1 : %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_he_IL.ts b/Plugins/ScriptingPython/translations/ScriptingPython_he_IL.ts
new file mode 100644
index 0000000..a6a6fd7
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_he_IL.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="he" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>שימוש לא תקין בפונקציה %1. הציפיה הייתה לקבלת משתנה %2, אך נתקבל %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>שגיאה לא ידועה מפונקציה %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>לא ניתן היה לחשב מחרוזות המייצגת את אובייקט פייתון שהועבר כמשתנה לפונקציה %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>לא ניתן למצוא הקשר הפעלת פונקציה %1. זהו תקל במתקע פייתון. נא לדווח על כך.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>שגיאת פונקציית פייתון %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_hu_HU.ts b/Plugins/ScriptingPython/translations/ScriptingPython_hu_HU.ts
new file mode 100644
index 0000000..e7b147d
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_hu_HU.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="hu" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_it_IT.ts b/Plugins/ScriptingPython/translations/ScriptingPython_it_IT.ts
new file mode 100644
index 0000000..c56d38c
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_it_IT.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="it" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>Uso non valido della funzione %1. Atteso %2 argomenti, ma ottenuto %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>Errore sconosciuto dalla funzione %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>Impossibile calcolare la rappresentazione della stringa dell&apos;oggetto Python passato come argomento alla funzione %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>Impossibile trovare il contesto di esecuzione per la funzione %1. Questo è un bug del plugin Python. Si prega di segnalarlo.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Errore dalla funzione Python %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_ja_JP.ts b/Plugins/ScriptingPython/translations/ScriptingPython_ja_JP.ts
new file mode 100644
index 0000000..a0487de
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_ja_JP.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ja" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_kaa.ts b/Plugins/ScriptingPython/translations/ScriptingPython_kaa.ts
new file mode 100644
index 0000000..77cf961
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_kaa.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="kaa" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_ko_KR.ts b/Plugins/ScriptingPython/translations/ScriptingPython_ko_KR.ts
new file mode 100644
index 0000000..caabe75
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_ko_KR.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ko" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_nl_NL.ts b/Plugins/ScriptingPython/translations/ScriptingPython_nl_NL.ts
new file mode 100644
index 0000000..9e43453
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_nl_NL.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="nl" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_no_NO.ts b/Plugins/ScriptingPython/translations/ScriptingPython_no_NO.ts
new file mode 100644
index 0000000..cb16c40
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_no_NO.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="no" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_pl_PL.ts b/Plugins/ScriptingPython/translations/ScriptingPython_pl_PL.ts
new file mode 100644
index 0000000..222819c
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_pl_PL.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="pl" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>Nieprawidłowe użycie funkcji %1. Oczekiwano %2 argumentów, ale otrzymano %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>Nieznany błąd z funkcji %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>Nie można przedstawić obiektu Pythona przekazanego jako argument do funkcji %1 jako reprezentacji ciągu znaków.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>Nie można odnaleźć kontekstu wykonania funkcji %1. Jest to błąd wtyczki Pythona. Proszę, zgłoś to.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Błąd z funkcji Pythona %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_pt_BR.ts b/Plugins/ScriptingPython/translations/ScriptingPython_pt_BR.ts
new file mode 100644
index 0000000..cc25e10
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_pt_BR.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="pt-BR" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>Uso inválido de %1 função. Esperado %2 argumentos, mas recebeu %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>Erro desconhecido da função %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>Não foi possível calcular a representação de cadeia de caracteres do objeto Python passado como argumento para a função %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>Não foi possível encontrar o contexto de execução para a função %1. Este é um erro do plugin Python. Por favor, relate o problema.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Erro da função Python %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_pt_PT.ts b/Plugins/ScriptingPython/translations/ScriptingPython_pt_PT.ts
new file mode 100644
index 0000000..02fc86c
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_pt_PT.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="pt-PT" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_ro_RO.ts b/Plugins/ScriptingPython/translations/ScriptingPython_ro_RO.ts
new file mode 100644
index 0000000..ae0dca8
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_ro_RO.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ro" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_ru_RU.ts b/Plugins/ScriptingPython/translations/ScriptingPython_ru_RU.ts
new file mode 100644
index 0000000..6994f5a
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_ru_RU.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ru" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>Некорректное использование функции %1. Ожидается аргументов: %2, передано аргументов: %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>Неизвестная ошибка при выполнении функции %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>Невозможно сформировать строковое представление объекта Python, переданного в виде аргумента в функцию %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>Не найден контекст выполнения для функции %1. Это ошибка модуля Python. Пожалуйста, сообщите о ней.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Ошибка при выполнении функции Python %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_sk_SK.ts b/Plugins/ScriptingPython/translations/ScriptingPython_sk_SK.ts
new file mode 100644
index 0000000..73ca8fb
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_sk_SK.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="sk" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_sr_SP.ts b/Plugins/ScriptingPython/translations/ScriptingPython_sr_SP.ts
new file mode 100644
index 0000000..dce058c
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_sr_SP.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="sr" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_sv_SE.ts b/Plugins/ScriptingPython/translations/ScriptingPython_sv_SE.ts
new file mode 100644
index 0000000..0808c90
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_sv_SE.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="sv-SE" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_tr_TR.ts b/Plugins/ScriptingPython/translations/ScriptingPython_tr_TR.ts
new file mode 100644
index 0000000..6d3c907
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_tr_TR.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="tr" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>%1 işlevinin geçersiz kullanımı. Beklenen %2 argümanları, ancak %3 var.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>%1 fonksiyonundan bilinmeyen hata.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>%1 işlevine bağımsız değişken olarak geçirilen Python nesnesinin dize gösterimi hesaplanamadı.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>%1 işlevinin yürütme içeriği bulunamadı. Bu bir Python eklentisi hatasıdır. Lütfen rapor edin.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Python işlevinden %1 hatası: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_uk_UA.ts b/Plugins/ScriptingPython/translations/ScriptingPython_uk_UA.ts
new file mode 100644
index 0000000..5c1c035
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_uk_UA.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="uk" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_vi_VN.ts b/Plugins/ScriptingPython/translations/ScriptingPython_vi_VN.ts
new file mode 100644
index 0000000..8a12cd0
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_vi_VN.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="vi" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation type="unfinished">Invalid use of %1 function. Expected %2 arguments, but got %3.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation type="unfinished">Unknown error from function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation type="unfinished">Could not calculate string representation of the Python object passed as argument to the function %1.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation type="unfinished">Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation type="unfinished">Error from Python function %1: %2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_zh_CN.ts b/Plugins/ScriptingPython/translations/ScriptingPython_zh_CN.ts
new file mode 100644
index 0000000..c9923a0
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_zh_CN.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="zh-CN" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>无效的 %1 函数用法。预期是 %2 参数,但实际是 %3。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>函数 %1 的未知错误。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>无法计算作为参数传递给 %1 函数的 Python 对象所表示的字符串。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>找不到函数 %1 的执行环境。这是 Python 插件的 bug,请报告该问题。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Python 函数 %1 错误:%2</translation>
+ </message>
+ </context>
+</TS>
diff --git a/Plugins/ScriptingPython/translations/ScriptingPython_zh_TW.ts b/Plugins/ScriptingPython/translations/ScriptingPython_zh_TW.ts
new file mode 100644
index 0000000..d8b9b89
--- /dev/null
+++ b/Plugins/ScriptingPython/translations/ScriptingPython_zh_TW.ts
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="zh-TW" sourcelanguage="en">
+ <context>
+ <name>QObject</name>
+ <message>
+ <location filename="../scriptingpython.cpp" line="484"/>
+ <source>Invalid use of %1 function. Expected %2 arguments, but got %3.</source>
+ <translation>無效的 %1 函式用法。期望 %2 個引數,得到 %3。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="493"/>
+ <source>Unknown error from function %1.</source>
+ <translation>函式 %1 的未知錯誤。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="534"/>
+ <source>Could not calculate string representation of the Python object passed as argument to the function %1.</source>
+ <translation>無法計算作為引數傳遞給函式 %1 的 Python 物件所表示的字串。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="550"/>
+ <source>Could not find execution context for function %1. This is a bug of Python plugin. Please report it.</source>
+ <translation>找不到函式 %1 的執行環境。這是 Python 外掛的 bug,請報告該問題。</translation>
+ </message>
+ <message>
+ <location filename="../scriptingpython.cpp" line="575"/>
+ <source>Error from Python function %1: %2</source>
+ <translation>Python 函式 %1 錯誤:%2</translation>
+ </message>
+ </context>
+</TS>