Add initial support for translations.

This commit is contained in:
Felix Geyer 2014-05-18 01:33:22 +02:00
parent becd3a0019
commit 28694ae687
15 changed files with 2634 additions and 1 deletions

8
.tx/config Normal file
View File

@ -0,0 +1,8 @@
[main]
host = https://www.transifex.com
[keepassx.keepassx_ents]
source_file = share/translations/keepassx_en.ts
file_filter = share/translations/keepassx_<lang>.ts
source_lang = en
type = QT

View File

@ -13,6 +13,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(translations)
file(GLOB DATABASE_ICONS icons/database/*.png) file(GLOB DATABASE_ICONS icons/database/*.png)
install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database) install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database)

View File

@ -0,0 +1,26 @@
# Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 or (at your option)
# version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
file(GLOB TRANSLATION_FILES *.ts)
get_filename_component(TRANSLATION_EN_ABS keepassx_en.ts ABSOLUTE)
list(REMOVE_ITEM TRANSLATION_FILES keepassx_en.ts)
list(REMOVE_ITEM TRANSLATION_FILES ${TRANSLATION_EN_ABS})
message(STATUS ${TRANSLATION_FILES})
qt4_add_translation(QM_FILES ${TRANSLATION_FILES})
install(FILES ${QM_FILES} DESTINATION ${DATA_INSTALL_DIR}/translations)
add_custom_target(translations DEPENDS ${QM_FILES})
add_dependencies(${PROGNAME} translations)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="en_US">
<context>
<name>DatabaseWidget</name>
<message numerus="yes">
<source>Do you really want to move %n entry(s) to the recycle bin?</source>
<translation>
<numerusform>Do you really want to move %n entry to the recycle bin?</numerusform>
<numerusform>Do you really want to move %n entries to the recycle bin?</numerusform>
</translation>
</message>
</context>
<context>
<name>EditEntryWidget</name>
<message numerus="yes">
<source>%n week(s)</source>
<translation>
<numerusform>%n week</numerusform>
<numerusform>%n weeks</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n month(s)</source>
<translation>
<numerusform>%n month</numerusform>
<numerusform>%n months</numerusform>
</translation>
</message>
</context>
<context>
<name>EditWidgetIcons</name>
<message numerus="yes">
<source>Can&apos;t delete icon. Still used by %n item(s).</source>
<translation>
<numerusform>Can&apos;t delete icon. Still used by %n item.</numerusform>
<numerusform>Can&apos;t delete icon. Still used by %n items.</numerusform>
</translation>
</message>
</context>
</TS>

8
share/translations/update.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
BASEDIR=$(dirname $0)
cd $BASEDIR/../..
lupdate -no-ui-lines -disable-heuristic similartext -locations none -no-obsolete src -ts share/translations/keepassx_en.ts
lupdate -no-ui-lines -disable-heuristic similartext -locations none -pluralonly src -ts share/translations/keepassx_en_plurals.ts

View File

@ -50,6 +50,7 @@ set(keepassx_SOURCES
core/TimeInfo.cpp core/TimeInfo.cpp
core/ToDbExporter.cpp core/ToDbExporter.cpp
core/Tools.cpp core/Tools.cpp
core/Translator.cpp
core/Uuid.cpp core/Uuid.cpp
core/qcommandlineoption.cpp core/qcommandlineoption.cpp
core/qcommandlineparser.cpp core/qcommandlineparser.cpp

View File

@ -6,6 +6,7 @@
#define KEEPASSX_VERSION "${KEEPASSX_VERSION}" #define KEEPASSX_VERSION "${KEEPASSX_VERSION}"
#define KEEPASSX_SOURCE_DIR "${CMAKE_SOURCE_DIR}" #define KEEPASSX_SOURCE_DIR "${CMAKE_SOURCE_DIR}"
#define KEEPASSX_BINARY_DIR "${CMAKE_BINARY_DIR}"
#define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}" #define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}"

View File

@ -102,6 +102,7 @@ void Config::init(const QString& fileName)
m_defaults.insert("security/lockdatabaseidlesec", 10); m_defaults.insert("security/lockdatabaseidlesec", 10);
m_defaults.insert("security/passwordscleartext", false); m_defaults.insert("security/passwordscleartext", false);
m_defaults.insert("security/autotypeask", true); m_defaults.insert("security/autotypeask", true);
m_defaults.insert("GUI/Language", "system");
} }
Config* Config::instance() Config* Config::instance()

120
src/core/Translator.cpp Normal file
View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Translator.h"
#include <QCoreApplication>
#include <QDir>
#include <QLibraryInfo>
#include <QLocale>
#include <QRegExp>
#include <QTranslator>
#include "config-keepassx.h"
#include "core/Config.h"
#include "core/FilePath.h"
void Translator::installTranslator()
{
QString language = config()->get("GUI/Language").toString();
if (language == "system" || language.isEmpty()) {
language = QLocale::system().name();
}
if (!installTranslator(language)) {
// English fallback still needs translations for plurals
if (!installTranslator("en_plurals")) {
qWarning("Couldn't load translations.");
}
}
installQtTranslator(language);
availableLanguages();
}
QList<QPair<QString, QString> > Translator::availableLanguages()
{
QStringList paths;
#ifdef QT_DEBUG
paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR));
#endif
paths.append(filePath()->dataPath("translations"));
QList<QPair<QString, QString> > languages;
languages.append(QPair<QString, QString>("system", "System default"));
QRegExp regExp("keepassx_([a-zA-Z_]+)\\.qm", Qt::CaseInsensitive, QRegExp::RegExp2);
Q_FOREACH (const QString& path, paths) {
Q_FOREACH (const QString& filename, QDir(path).entryList()) {
if (regExp.exactMatch(filename)) {
QString langcode = regExp.cap(1);
if (langcode == "en_plurals") {
langcode = "en";
}
languages.append(QPair<QString, QString>(langcode,
QLocale::languageToString(QLocale(langcode).language())));
}
}
}
return languages;
}
bool Translator::installTranslator(const QString& language)
{
QStringList paths;
#ifdef QT_DEBUG
paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR));
#endif
paths.append(filePath()->dataPath("translations"));
Q_FOREACH (const QString& path, paths) {
if (installTranslator(language, path)) {
return true;
}
}
return false;
}
bool Translator::installTranslator(const QString& language, const QString& path)
{
QTranslator* translator = new QTranslator(qApp);
if (translator->load(QString("keepassx_").append(language), path)) {
QCoreApplication::installTranslator(translator);
return true;
}
else {
delete translator;
return false;
}
}
bool Translator::installQtTranslator(const QString& language)
{
QTranslator* qtTranslator = new QTranslator(qApp);
if (qtTranslator->load(QString("%1/qt_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) {
QCoreApplication::installTranslator(qtTranslator);
return true;
}
else {
delete qtTranslator;
return false;
}
}

36
src/core/Translator.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_TRANSLATOR_H
#define KEEPASSX_TRANSLATOR_H
#include <QPair>
#include <QString>
class Translator
{
public:
static void installTranslator();
static QList<QPair<QString, QString> > availableLanguages();
private:
static bool installTranslator(const QString& language);
static bool installTranslator(const QString& language, const QString& path);
static bool installQtTranslator(const QString& language);
};
#endif // KEEPASSX_TRANSLATOR_H

View File

@ -21,6 +21,7 @@
#include "autotype/AutoType.h" #include "autotype/AutoType.h"
#include "core/Config.h" #include "core/Config.h"
#include "core/Translator.h"
SettingsWidget::SettingsWidget(QWidget* parent) SettingsWidget::SettingsWidget(QWidget* parent)
: EditWidget(parent) : EditWidget(parent)
@ -69,6 +70,15 @@ void SettingsWidget::loadSettings()
m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool()); m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool());
m_generalUi->autoTypeEntryTitleMatchCheckBox->setChecked(config()->get("AutoTypeEntryTitleMatch").toBool()); m_generalUi->autoTypeEntryTitleMatchCheckBox->setChecked(config()->get("AutoTypeEntryTitleMatch").toBool());
QList<QPair<QString, QString> > languages = Translator::availableLanguages();
for (int i = 0; i < languages.size(); i++) {
m_generalUi->languageComboBox->addItem(languages[i].second, languages[i].first);
}
int defaultIndex = m_generalUi->languageComboBox->findData(config()->get("GUI/Language"));
if (defaultIndex > 0) {
m_generalUi->languageComboBox->setCurrentIndex(defaultIndex);
}
if (autoType()->isAvailable()) { if (autoType()->isAvailable()) {
m_globalAutoTypeKey = static_cast<Qt::Key>(config()->get("GlobalAutoTypeKey").toInt()); m_globalAutoTypeKey = static_cast<Qt::Key>(config()->get("GlobalAutoTypeKey").toInt());
m_globalAutoTypeModifiers = static_cast<Qt::KeyboardModifiers>(config()->get("GlobalAutoTypeModifiers").toInt()); m_globalAutoTypeModifiers = static_cast<Qt::KeyboardModifiers>(config()->get("GlobalAutoTypeModifiers").toInt());
@ -105,6 +115,8 @@ void SettingsWidget::saveSettings()
m_generalUi->useGroupIconOnEntryCreationCheckBox->isChecked()); m_generalUi->useGroupIconOnEntryCreationCheckBox->isChecked());
config()->set("AutoTypeEntryTitleMatch", config()->set("AutoTypeEntryTitleMatch",
m_generalUi->autoTypeEntryTitleMatchCheckBox->isChecked()); m_generalUi->autoTypeEntryTitleMatchCheckBox->isChecked());
int currentLangIndex = m_generalUi->languageComboBox->currentIndex();
config()->set("GUI/Language", m_generalUi->languageComboBox->itemData(currentLangIndex).toString());
if (autoType()->isAvailable()) { if (autoType()->isAvailable()) {
config()->set("GlobalAutoTypeKey", m_generalUi->autoTypeShortcutWidget->key()); config()->set("GlobalAutoTypeKey", m_generalUi->autoTypeShortcutWidget->key());
config()->set("GlobalAutoTypeModifiers", config()->set("GlobalAutoTypeModifiers",

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>456</width> <width>456</width>
<height>230</height> <height>288</height>
</rect> </rect>
</property> </property>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
@ -86,6 +86,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0">
<widget class="QLabel" name="languageLabel">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QComboBox" name="languageComboBox"/>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>

View File

@ -21,6 +21,7 @@
#include "core/Config.h" #include "core/Config.h"
#include "core/qcommandlineparser.h" #include "core/qcommandlineparser.h"
#include "core/Tools.h" #include "core/Tools.h"
#include "core/Translator.h"
#include "crypto/Crypto.h" #include "crypto/Crypto.h"
#include "gui/Application.h" #include "gui/Application.h"
#include "gui/MainWindow.h" #include "gui/MainWindow.h"
@ -66,6 +67,8 @@ int main(int argc, char** argv)
Config::createConfigFromFile(parser.value(configOption)); Config::createConfigFromFile(parser.value(configOption));
} }
Translator::installTranslator();
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
// Don't show menu icons on OSX // Don't show menu icons on OSX
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);