diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index 30cb65d7..1a366a97 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -194,8 +194,9 @@ /*! Constructs the DeviceManager with the given \a parent. There should only be one DeviceManager in the system created by \l{guhserver::GuhCore}. * Use \c guhserver::GuhCore::instance()->deviceManager() instead to access the DeviceManager. */ -DeviceManager::DeviceManager(QObject *parent) : +DeviceManager::DeviceManager(const QLocale &locale, QObject *parent) : QObject(parent), + m_locale(locale), m_radio433(0) { qRegisterMetaType(); @@ -986,6 +987,9 @@ void DeviceManager::loadPlugins() continue; } + pluginIface->setLocale(m_locale); + qApp->installTranslator(pluginIface->translator()); + if (verifyPluginMetadata(loader.metaData().value("MetaData").toObject())) { pluginIface->initPlugin(loader.metaData().value("MetaData").toObject(), this); qCDebug(dcDeviceManager) << "**** Loaded plugin" << pluginIface->pluginName(); diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index f1d06198..438a1912 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -43,6 +43,7 @@ #include #include +#include #include class Device; @@ -102,7 +103,7 @@ public: DeviceSetupStatusAsync }; - explicit DeviceManager(QObject *parent = 0); + explicit DeviceManager(const QLocale &locale, QObject *parent = 0); ~DeviceManager(); static QStringList pluginSearchDirs(); @@ -189,6 +190,7 @@ private: void postSetupDevice(Device *device); private: + QLocale m_locale; QHash m_supportedVendors; QHash > m_vendorDeviceMap; QHash m_supportedDevices; diff --git a/libguh/guhsettings.cpp b/libguh/guhsettings.cpp index 5ac924ce..97e9078b 100644 --- a/libguh/guhsettings.cpp +++ b/libguh/guhsettings.cpp @@ -186,6 +186,11 @@ QString GuhSettings::settingsPath() return path; } +QString GuhSettings::translationsPath() +{ + return QString("/usr/share/guh/translations"); +} + /*! Returns the path where the log file (console log) will be stored. */ QString GuhSettings::consoleLogPath() { diff --git a/libguh/guhsettings.h b/libguh/guhsettings.h index 0c8cb984..b5aa7da1 100644 --- a/libguh/guhsettings.h +++ b/libguh/guhsettings.h @@ -48,6 +48,7 @@ public: static bool isRoot(); static QString logPath(); static QString settingsPath(); + static QString translationsPath(); static QString consoleLogPath(); // forwarded QSettings methods diff --git a/libguh/plugin/deviceplugin.cpp b/libguh/plugin/deviceplugin.cpp index f5a33e7c..3d151fe8 100644 --- a/libguh/plugin/deviceplugin.cpp +++ b/libguh/plugin/deviceplugin.cpp @@ -148,7 +148,8 @@ /*! DevicePlugin constructor. DevicePlugins will be instantiated by the DeviceManager, its \a parent. */ DevicePlugin::DevicePlugin(QObject *parent): - QObject(parent) + QObject(parent), + m_translator(new QTranslator(this)) { } @@ -440,6 +441,16 @@ QList DevicePlugin::supportedDevices() const return deviceClasses; } +QTranslator *DevicePlugin::translator() +{ + return m_translator; +} + +void DevicePlugin::setLocale(const QLocale &locale) +{ + m_translator->load(locale, pluginName(), "_", GuhSettings::translationsPath(), ".qm"); +} + /*! Override this if your plugin supports Device with DeviceClass::CreationMethodAuto. This will be called at startup, after the configured devices have been loaded. This is the earliest time you should start emitting autoDevicesAppeared(). If you diff --git a/libguh/plugin/deviceplugin.h b/libguh/plugin/deviceplugin.h index 0d2468ca..3430b6c5 100644 --- a/libguh/plugin/deviceplugin.h +++ b/libguh/plugin/deviceplugin.h @@ -41,6 +41,7 @@ #include #include #include +#include #include class DeviceManager; @@ -60,6 +61,9 @@ public: QList supportedVendors() const; QList supportedDevices() const; + QTranslator *translator(); + void setLocale(const QLocale &locale); + virtual DeviceManager::HardwareResources requiredHardware() const = 0; virtual void startMonitoringAutoDevices(); @@ -137,6 +141,7 @@ private: QPair loadAndVerifyBasicTag(const QString &basicTag) const; QPair loadAndVerifyDeviceIcon(const QString &deviceIcon) const; + QTranslator *m_translator; DeviceManager *m_deviceManager; QList m_configurationDescription; diff --git a/plugins/plugins.pri b/plugins/plugins.pri index 7dd6801b..57ede013 100644 --- a/plugins/plugins.pri +++ b/plugins/plugins.pri @@ -5,7 +5,12 @@ CONFIG += plugin QT += network -INCLUDEPATH += ../../../libguh +# Check Bluetooth LE support +contains(DEFINES, BLUETOOTH_LE) { + QT += bluetooth +} + +INCLUDEPATH += $$top_srcdir/libguh LIBS += -L../../../libguh -lguh infofile.output = plugininfo.h diff --git a/server/guhcore.cpp b/server/guhcore.cpp index 98126135..e7bcafc8 100644 --- a/server/guhcore.cpp +++ b/server/guhcore.cpp @@ -381,6 +381,12 @@ ServerManager *GuhCore::serverManager() const return m_serverManager; } +QStringList GuhCore::getAvailableLanguages() +{ + // TODO: parse available translation files + return QStringList() << "en_US" << "de_DE"; +} + BluetoothServer *GuhCore::bluetoothServer() const { return m_bluetoothServer; @@ -416,7 +422,7 @@ GuhCore::GuhCore(QObject *parent) : m_cloudManager = new CloudManager(m_configuration->cloudEnabled(), m_configuration->cloudAuthenticationServer(), m_configuration->cloudProxyServer(), this); qCDebug(dcApplication) << "Creating Device Manager"; - m_deviceManager = new DeviceManager(this); + m_deviceManager = new DeviceManager(m_configuration->locale(), this); qCDebug(dcApplication) << "Creating Rule Engine"; m_ruleEngine = new RuleEngine(this); diff --git a/server/guhcore.h b/server/guhcore.h index dc0ce1e6..b287ac48 100644 --- a/server/guhcore.h +++ b/server/guhcore.h @@ -87,6 +87,7 @@ public: ServerManager *serverManager() const; BluetoothServer *bluetoothServer() const; + static QStringList getAvailableLanguages(); #ifdef TESTING_ENABLED MockTcpServer *tcpServer() const; diff --git a/server/jsonrpc/configurationhandler.cpp b/server/jsonrpc/configurationhandler.cpp index e41062e5..4b203faf 100644 --- a/server/jsonrpc/configurationhandler.cpp +++ b/server/jsonrpc/configurationhandler.cpp @@ -33,6 +33,12 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): returns.insert("timeZones", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); setReturns("GetTimeZones", returns); + params.clear(); returns.clear(); + setDescription("GetAvailableLanguages", "Returns a list of locale codes available for the server. i.e. en_US, de_AT"); + setParams("GetAvailableLanguages", params); + returns.insert("languages", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); + setReturns("GetAvailableLanguages", returns); + params.clear(); returns.clear(); setDescription("GetConfigurations", "Get all configuration parameters of the server."); setParams("GetConfigurations", params); @@ -41,6 +47,7 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): basicConfiguration.insert("serverUuid", JsonTypes::basicTypeToString(JsonTypes::Uuid)); basicConfiguration.insert("serverTime", JsonTypes::basicTypeToString(JsonTypes::Uint)); basicConfiguration.insert("timeZone", JsonTypes::basicTypeToString(JsonTypes::String)); + basicConfiguration.insert("language", JsonTypes::basicTypeToString(JsonTypes::String)); returns.insert("basicConfiguration", basicConfiguration); QVariantMap tcpServerConfiguration; tcpServerConfiguration.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); @@ -73,6 +80,13 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): returns.insert("configurationError", JsonTypes::configurationErrorRef()); setReturns("SetTimeZone", returns); + params.clear(); returns.clear(); + setDescription("SetLanguage", "Sets the server language to the given language. See also: \"GetAvailableLanguages\""); + params.insert("language", JsonTypes::basicTypeToString(JsonTypes::String)); + setParams("SetLanguage", params); + returns.insert("configurationError", JsonTypes::configurationErrorRef()); + setReturns("SetLanguage", returns); + params.clear(); returns.clear(); setDescription("SetTcpServerConfiguration", "Configure the TCP interface of the server. Note: if you are using the TCP server for this call you will loose the connection."); params.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); @@ -124,8 +138,9 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); setParams("WebSocketServerConfigurationChanged", params); - connect(GuhCore::instance()->configuration(), &GuhConfiguration::timeZoneChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(GuhCore::instance()->configuration(), &GuhConfiguration::serverNameChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); + connect(GuhCore::instance()->configuration(), &GuhConfiguration::timeZoneChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); + connect(GuhCore::instance()->configuration(), &GuhConfiguration::localeChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(GuhCore::instance()->configuration(), &GuhConfiguration::tcpServerConfigurationChanged, this, &ConfigurationHandler::onTcpServerConfigurationChanged); connect(GuhCore::instance()->configuration(), &GuhConfiguration::webServerConfigurationChanged, this, &ConfigurationHandler::onWebServerConfigurationChanged); connect(GuhCore::instance()->configuration(), &GuhConfiguration::webSocketServerConfigurationChanged, this, &ConfigurationHandler::onWebSocketServerConfigurationChanged); @@ -163,6 +178,18 @@ JsonReply *ConfigurationHandler::GetTimeZones(const QVariantMap ¶ms) const return createReply(returns); } +JsonReply *ConfigurationHandler::GetAvailableLanguages(const QVariantMap ¶ms) const +{ + Q_UNUSED(params) + QVariantList languages; + foreach (const QString &language, GuhCore::getAvailableLanguages()) { + languages.append(language); + } + QVariantMap returns; + returns.insert("languages", languages); + return createReply(returns); +} + JsonReply *ConfigurationHandler::SetServerName(const QVariantMap ¶ms) const { QString serverName = params.value("serverName").toString(); @@ -182,6 +209,16 @@ JsonReply *ConfigurationHandler::SetTimeZone(const QVariantMap ¶ms) const return createReply(statusToReply(GuhConfiguration::ConfigurationErrorNoError)); } +JsonReply *ConfigurationHandler::SetLanguage(const QVariantMap ¶ms) const +{ + qCDebug(dcJsonRpc()) << "Setting language to" << params.value("language").toString(); + QLocale locale(params.value("language").toString()); + + GuhCore::instance()->configuration()->setLocale(locale); + + return createReply(statusToReply(GuhConfiguration::ConfigurationErrorNoError)); +} + JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap ¶ms) const { QHostAddress host = QHostAddress(params.value("host").toString()); diff --git a/server/jsonrpc/configurationhandler.h b/server/jsonrpc/configurationhandler.h index 4c55005a..c324ae34 100644 --- a/server/jsonrpc/configurationhandler.h +++ b/server/jsonrpc/configurationhandler.h @@ -37,8 +37,10 @@ public: Q_INVOKABLE JsonReply *GetConfigurations(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *GetTimeZones(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetAvailableLanguages(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetServerName(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetTimeZone(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetLanguage(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetTcpServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetWebServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetWebSocketServerConfiguration(const QVariantMap ¶ms) const; diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index fdd4f181..eaba3e5e 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -270,8 +270,11 @@ void JsonRPCServer::clientConnected(const QUuid &clientId) QVariantMap handshake; handshake.insert("id", 0); - handshake.insert("server", "guh JSONRPC interface"); + handshake.insert("server", "guhIO"); + handshake.insert("name", GuhCore::instance()->configuration()->serverName()); handshake.insert("version", GUH_VERSION_STRING); + handshake.insert("uuid", GuhCore::instance()->configuration()->serverUuid().toString()); + handshake.insert("language", GuhCore::instance()->configuration()->locale().name()); handshake.insert("protocol version", JSON_PROTOCOL_VERSION); interface->sendData(clientId, handshake); } diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index 40750480..86a1b25c 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -1003,6 +1003,7 @@ QVariantMap JsonTypes::packBasicConfiguration() basicConfiguration.insert("serverUuid", GuhCore::instance()->configuration()->serverUuid()); basicConfiguration.insert("serverTime", GuhCore::instance()->timeManager()->currentDateTime().toTime_t()); basicConfiguration.insert("timeZone", QString::fromUtf8(GuhCore::instance()->timeManager()->timeZone())); + basicConfiguration.insert("language", GuhCore::instance()->configuration()->locale().name()); return basicConfiguration; } diff --git a/server/main.cpp b/server/main.cpp index 5bf9cce9..5d298b1e 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -145,7 +145,7 @@ int main(int argc, char *argv[]) QCommandLineOption foregroundOption(QStringList() << "n" << "no-daemon", QCoreApplication::translate("main", "Run guhd in the foreground, not as daemon.")); parser.addOption(foregroundOption); - QString debugDescription = QString("Debug categories to enable. Prefix with \"No\" to disable. Warnings from all categories will be printed unless explicitly muted with \"NoWarnings\". \n\nCategories are:"); + QString debugDescription = QCoreApplication::translate("main", "Debug categories to enable. Prefix with \"No\" to disable. Warnings from all categories will be printed unless explicitly muted with \"NoWarnings\". \n\nCategories are:"); // create sorted loggingFiler list QStringList sortedFilterList = QStringList(s_loggingFilters.keys()); diff --git a/server/server.pro b/server/server.pro index d47bf2e5..6aa03bb1 100644 --- a/server/server.pro +++ b/server/server.pro @@ -12,6 +12,13 @@ QT += sql xml websockets bluetooth LIBS += -L$$top_builddir/libguh/ -lguh +# Translations +TRANSLATIONS *= $$top_srcdir/translations/guhd_en_US.ts \ + $$top_srcdir/translations/guhd_de_DE.ts + +include(../translations.pri) + +# Server files include(server.pri) include(qtservice/qtservice.pri) diff --git a/translations.pri b/translations.pri new file mode 100644 index 00000000..b2975f05 --- /dev/null +++ b/translations.pri @@ -0,0 +1,17 @@ +include(guh.pri) + +# Create translation files +lrelease.input = TRANSLATIONS +lrelease.output = $$top_srcdir/${QMAKE_FILE_BASE}.qm +lrelease.commands = $$[QT_INSTALL_BINS]/lupdate ${QMAKE_FILE_IN} -ts $$TRANSLATIONS; $$[QT_INSTALL_BINS]/lrelease ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.qm +lrelease.CONFIG += no_link + +QMAKE_EXTRA_COMPILERS += lrelease +PRE_TARGETDEPS += compiler_lrelease_make_all + +message("Translations:" $$TRANSLATIONS ) + +translations.path = /usr/share/guh/translations +translations.files = $$[QT_SOURCE_TREE]/translations/*.qm + +INSTALLS += translations diff --git a/translations/guhd_de_DE.ts b/translations/guhd_de_DE.ts new file mode 100644 index 00000000..c26e3ba7 --- /dev/null +++ b/translations/guhd_de_DE.ts @@ -0,0 +1,20 @@ + + + + + main + + + Run guhd in the foreground, not as daemon. + Starte guhd im Vordergrund, nicht als service. + + + + Debug categories to enable. Prefix with "No" to disable. Warnings from all categories will be printed unless explicitly muted with "NoWarnings". + +Categories are: + Zu aktivierende Debug-Kategorien. Kategorien mit dem Präfix "No" werden deaktiviert. Warnungen werden von allen Kategorien ausgegeben außer sie wurden explizit mit dem Prefix "NoWarnings" deaktiviert. +Kategorien sind: + + + diff --git a/translations/guhd_en_US.ts b/translations/guhd_en_US.ts new file mode 100644 index 00000000..558e5d3e --- /dev/null +++ b/translations/guhd_en_US.ts @@ -0,0 +1,19 @@ + + + + + main + + + Run guhd in the foreground, not as daemon. + + + + + Debug categories to enable. Prefix with "No" to disable. Warnings from all categories will be printed unless explicitly muted with "NoWarnings". + +Categories are: + + + +