Add translations support (#82)

* Add translations support
* Update .gitignore
This commit is contained in:
Jonas Kvinge 2019-02-22 20:24:38 +01:00 committed by GitHub
parent 034b032cfa
commit 954e0e8a59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 401 additions and 103 deletions

2
.gitignore vendored
View File

@ -106,6 +106,8 @@ PKGBUILD
# Translations
translations.pot
zanata.xml
.zanata-cache/
# Snap
parts/

View File

@ -114,6 +114,7 @@ pkg_check_modules(LIBUSBMUXD libusbmuxd)
pkg_check_modules(LIBPLIST libplist)
pkg_check_modules(LIBDEEZER libdeezer)
pkg_check_modules(LIBDZMEDIA libdzmedia)
find_package(Gettext)
if(WIN32)
find_package(ZLIB REQUIRED)
@ -151,6 +152,11 @@ if(WIN32)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::WinExtras)
endif()
find_package(Qt5LinguistTools CONFIG)
if (Qt5LinguistTools_FOUND)
set(QT_LCONVERT_EXECUTABLE Qt5::lconvert)
endif()
if(X11_FOUND)
find_path(KEYSYMDEF_H NAMES "keysymdef.h" PATHS "${X11_INCLUDE_DIR}" PATH_SUFFIXES "X11")
find_path(XF86KEYSYM_H NAMES "XF86keysym.h" PATHS "${XCB_INCLUDEDIR}" PATH_SUFFIXES "X11")
@ -346,6 +352,11 @@ optional_component(SPARKLE ON "Sparkle integration"
DEPENDS "Sparkle" SPARKLE
)
optional_component(TRANSLATIONS OFF "Translations (No languages included yet)"
DEPENDS "gettext" GETTEXT_FOUND
DEPENDS "Qt5LinguistTools" Qt5LinguistTools_FOUND
)
optional_component(STREAM_TIDAL ON "Streaming: Tidal support")
if (LIBDZMEDIA_FOUND OR LIBDEEZER_FOUND)

77
cmake/Translations.cmake Normal file
View File

@ -0,0 +1,77 @@
cmake_minimum_required(VERSION 2.8.11)
find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
if(NOT GETTEXT_XGETTEXT_EXECUTABLE)
message(FATAL_ERROR "Could not find xgettext executable")
endif(NOT GETTEXT_XGETTEXT_EXECUTABLE)
set (XGETTEXT_OPTIONS
--qt
--keyword=tr:1,2c
--keyword=tr --flag=tr:1:pass-c-format --flag=tr:1:pass-qt-format
--keyword=trUtf8 --flag=tr:1:pass-c-format --flag=tr:1:pass-qt-format
--keyword=translate:2,3c
--keyword=translate:2 --flag=translate:2:pass-c-format --flag=translate:2:pass-qt-format
--keyword=QT_TR_NOOP --flag=QT_TR_NOOP:1:pass-c-format --flag=QT_TR_NOOP:1:pass-qt-format
--keyword=QT_TRANSLATE_NOOP:2 --flag=QT_TRANSLATE_NOOP:2:pass-c-format --flag=QT_TRANSLATE_NOOP:2:pass-qt-format
--keyword=_ --flag=_:1:pass-c-format --flag=_:1:pass-qt-format
--keyword=N_ --flag=N_:1:pass-c-format --flag=N_:1:pass-qt-format
--from-code=utf-8
)
macro(add_pot outfiles header pot)
# Make relative filenames for all source files
set(add_pot_sources)
foreach(_filename ${ARGN})
get_filename_component(_absolute_filename ${_filename} ABSOLUTE)
file(RELATIVE_PATH _relative_filename ${CMAKE_CURRENT_SOURCE_DIR} ${_absolute_filename})
list(APPEND add_pot_sources ${_relative_filename})
endforeach(_filename)
# Generate the .pot
add_custom_command(
OUTPUT ${pot}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -s -C --omit-header --output=${CMAKE_CURRENT_BINARY_DIR}/pot.temp ${add_pot_sources}
COMMAND cat ${header} ${CMAKE_CURRENT_BINARY_DIR}/pot.temp > ${pot}
DEPENDS ${add_pot_sources} ${header}
)
list(APPEND ${outfiles} ${pot})
endmacro(add_pot)
# Syntax is:
# add_po(sources_var po_prefix LANGUAGES language1 language2 ... DIRECTORY dir)
macro(add_po outfiles po_prefix)
parse_arguments(ADD_PO
"LANGUAGES;DIRECTORY"
""
${ARGN}
)
foreach (_lang ${ADD_PO_LANGUAGES})
set(_po_filename "${_lang}.po")
set(_po_filepath "${CMAKE_CURRENT_SOURCE_DIR}/${ADD_PO_DIRECTORY}/${_po_filename}")
set(_qm_filename "strawberry_${_lang}.qm")
set(_qm_filepath "${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/${_qm_filename}")
# Convert the .po files to .qm files
add_custom_command(
OUTPUT ${_qm_filepath}
COMMAND ${QT_LCONVERT_EXECUTABLE} ARGS ${_po_filepath} -o ${_qm_filepath} -of qm
DEPENDS ${_po_filepath} ${_po_filepath}
)
list(APPEND ${outfiles} ${_qm_filepath})
endforeach (_lang)
# Generate a qrc file for the translations
set(_qrc ${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/translations.qrc)
file(WRITE ${_qrc} "<RCC><qresource prefix=\"/${ADD_PO_DIRECTORY}\">")
foreach(_lang ${ADD_PO_LANGUAGES})
file(APPEND ${_qrc} "<file>${po_prefix}${_lang}.qm</file>")
endforeach(_lang)
file(APPEND ${_qrc} "</qresource></RCC>")
qt5_add_resources(${outfiles} ${_qrc})
endmacro(add_po)

View File

@ -1,18 +1,18 @@
/* This file is part of Clementine.
/* This file is part of Strawberry.
Copyright 2016, John Maguire <john.maguire@gmail.com>
Clementine is free software: you can redistribute it and/or modify
Strawberry 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 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
Strawberry 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LAZY_H

View File

@ -26,6 +26,10 @@ if(BUILD_WERROR)
endif (LINUX)
endif(BUILD_WERROR)
if(HAVE_TRANSLATIONS)
include(../cmake/Translations.cmake)
endif(HAVE_TRANSLATIONS)
# Set up definitions and paths
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
@ -904,6 +908,37 @@ qt5_wrap_cpp(MOC ${HEADERS})
qt5_wrap_ui(UIC ${UI})
qt5_add_resources(QRC ${RESOURCES})
if(HAVE_TRANSLATIONS)
set(LINGUAS "All" CACHE STRING "A space-seperated list of translations to compile in to Strawberry, or \"None\".")
if (LINGUAS STREQUAL "All")
# build LANGUAGES from all existing .po files
file(GLOB pofiles translations/*.po)
foreach(pofile ${pofiles})
get_filename_component(lang ${pofile} NAME_WE)
list(APPEND LANGUAGES ${lang})
endforeach(pofile)
else (LINGUAS STREQUAL "All")
if (NOT LINGUAS OR LINGUAS STREQUAL "None")
set (LANGUAGES "")
else (NOT LINGUAS OR LINGUAS STREQUAL "None")
string(REGEX MATCHALL [a-zA-Z_@]+ LANGUAGES ${LINGUAS})
endif (NOT LINGUAS OR LINGUAS STREQUAL "None")
endif (LINGUAS STREQUAL "All")
add_pot(POT
${CMAKE_CURRENT_SOURCE_DIR}/translations/header
${CMAKE_CURRENT_SOURCE_DIR}/translations/translations.pot
${SOURCES}
${MOC}
${UIC}
${OTHER_SOURCES}
../data/html/oauthsuccess.html
)
add_po(PO strawberry_ LANGUAGES ${LANGUAGES} DIRECTORY translations)
endif(HAVE_TRANSLATIONS)
add_library(strawberry_lib STATIC
${SOURCES}
${MOC}

View File

@ -60,5 +60,6 @@
#define USE_BUNDLE_DIR "${USE_BUNDLE_DIR}"
#endif // CONFIG_H_IN
#cmakedefine HAVE_TRANSLATIONS
#endif // CONFIG_H_IN

View File

@ -232,9 +232,9 @@ void ContextView::NoSong() {
"font-weight: Regular;"
);
ui_->label_stop_top->setText("No song playing");
ui_->label_stop_top->setText(tr("No song playing"));
QString html = QString(
QString html = tr(
"%1 songs<br />\n"
"%2 artists<br />\n"
"%3 albums<br />\n"
@ -404,7 +404,7 @@ void ContextView::SetSong(const Song &song) {
if (albumlist.count() > 1) {
ui_->label_play_albums->setVisible(true);
ui_->label_play_albums->setMinimumSize(0, 20);
ui_->label_play_albums->setText(QString("<b>Albums by %1</b>").arg( song.artist().toHtmlEscaped()));
ui_->label_play_albums->setText(tr("<b>Albums by %1</b>").arg( song.artist().toHtmlEscaped()));
ui_->label_play_albums->setStyleSheet("background-color: #3DADE8; color: rgb(255, 255, 255); font: 11pt;");
for (CollectionBackend::Album album : albumlist) {
SongList songs = app_->collection_backend()->GetSongs(song.artist(), album.album_name, opt);

View File

@ -1,18 +1,18 @@
/* This file is part of Clementine.
/* This file is part of Strawberry.
Copyright 2015, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
Strawberry 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 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
Strawberry 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"

View File

@ -1,22 +1,22 @@
/* This file is part of Clementine.
/* This file is part of Strawberry.
Copyright 2015, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
Strawberry 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 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
Strawberry 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CORE_THREAD_H_
#define CORE_THREAD_H_
#ifndef THREAD_H
#define THREAD_H
#include "config.h"
@ -40,4 +40,4 @@ class Thread : public QThread {
Utilities::IoPriority io_priority_;
};
#endif // CORE_THREAD_H_
#endif // THREAD_H

View File

@ -58,6 +58,9 @@
#include <QSettings>
#include <QtEvents>
#include <QtDebug>
#ifdef HAVE_TRANSLATIONS
# include <QTranslator>
#endif
#ifdef Q_OS_LINUX
# include <unistd.h>
@ -96,6 +99,10 @@
# include "scoped_cftyperef.h"
#endif
#ifdef HAVE_TRANSLATIONS
# include "potranslator.h"
#endif
namespace Utilities {
static QString tr(const char *str) {
@ -764,6 +771,29 @@ QString DesktopEnvironment() {
}
#ifdef HAVE_TRANSLATIONS
QString SystemLanguageName() {
QString system_language = QLocale::system().uiLanguages().empty() ? QLocale::system().name() : QLocale::system().uiLanguages().first();
// uiLanguages returns strings with "-" as separators for language/region; however QTranslator needs "_" separators
system_language.replace("-", "_");
return system_language;
}
void LoadTranslation(const QString &prefix, const QString &path, const QString &language) {
QTranslator *t = new PoTranslator;
if (t->load(prefix + "_" + language, path))
QCoreApplication::installTranslator(t);
else
delete t;
}
#endif
} // namespace Utilities
ScopedWCharArray::ScopedWCharArray(const QString &str)

View File

@ -154,6 +154,11 @@ QString GetRandomString(const int len, const QString &UseCharacters);
QString DesktopEnvironment();
#ifdef HAVE_TRANSLATIONS
QString SystemLanguageName();
void LoadTranslation(const QString &prefix, const QString &path, const QString &language);
#endif
} // namespace
class ScopedWCharArray {

View File

@ -460,7 +460,7 @@ void DeezerService::ClearSearch() {
void DeezerService::SendSearch() {
emit UpdateStatus("Searching...");
emit UpdateStatus(tr("Searching..."));
QList<Param> parameters;
parameters << Param("q", search_text_);
@ -503,7 +503,7 @@ void DeezerService::SearchFinished(QNetworkReply *reply, int id) {
QJsonArray json_data = json_value.toArray();
if (json_data.isEmpty()) {
Error("No match.");
Error(tr("No match."));
CheckFinish();
return;
}
@ -588,7 +588,8 @@ void DeezerService::SearchFinished(QNetworkReply *reply, int id) {
}
if (albums_requested_ > 0) {
emit UpdateStatus(QString("Retrieving %1 album%2...").arg(albums_requested_).arg(albums_requested_ == 1 ? "" : "s"));
if (albums_requested_ == 1) emit UpdateStatus(tr("Retrieving %1 album...").arg(albums_requested_));
else emit UpdateStatus(tr("Retrieving %1 albums...").arg(albums_requested_));
emit ProgressSetMaximum(albums_requested_);
emit UpdateProgress(0);
}

View File

@ -1,19 +1,22 @@
/* This file is part of Clementine.
Copyright 2016, Valeriy Malov <jazzvoid@gmail.com>
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2016, Valeriy Malov <jazzvoid@gmail.com>
*
* Strawberry 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 3 of the License, or
* (at your option) any later version.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"

View File

@ -1,19 +1,22 @@
/* This file is part of Clementine.
Copyright 2016, Valeriy Malov <jazzvoid@gmail.com>
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2016, Valeriy Malov <jazzvoid@gmail.com>
*
* Strawberry 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 3 of the License, or
* (at your option) any later version.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef UDISKS2LISTER_H
#define UDISKS2LISTER_H

View File

@ -75,7 +75,7 @@ About::About(QWidget *parent):QDialog(parent) {
<< Person("Valeriy Malov", "jazzvoid@gmail.com")
<< Person("Nick Lanham", "nick@afternight.org");
QString Title("About Strawberry");
QString Title(tr("About Strawberry"));
QFont title_font;
title_font.setBold(true);
@ -99,28 +99,27 @@ QString About::MainHtml() const {
QString ret;
ret = QString("<p>Version %1</p>").arg(QCoreApplication::applicationVersion());
ret = tr("<p>Version %1</p>").arg(QCoreApplication::applicationVersion());
ret += QString("<p>");
ret += QString("Strawberry is a audio player and music collection organizer.<br />");
ret += QString("It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles.<br />");
ret += QString("The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.");
ret += QString("</p>");
//ret += QString("<p>Website: <a href=\"http://www.strawbs.org/licenses/\">http://www.strawbs.org/</a></p>");
ret += QString("<p>");
ret += QString("Strawberry is free software: you can redistribute it and/or modify<br />");
ret += QString("it under the terms of the GNU General Public License as published by<br />");
ret += QString("the Free Software Foundation, either version 3 of the License, or<br />");
ret += QString("(at your option) any later version.<br />");
ret += QString("<br />");
ret += QString("Strawberry is distributed in the hope that it will be useful,<br />");
ret += QString("but WITHOUT ANY WARRANTY; without even the implied warranty of<br />");
ret += QString("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />");
ret += QString("GNU General Public License for more details.<br />");
ret += QString("<br />");
ret += QString("You should have received a copy of the GNU General Public License<br />");
ret += QString("along with Strawberry. If not, see <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses/</a>.");
ret += QString("</p>");
ret += "<p>";
ret += tr("Strawberry is a audio player and music collection organizer.<br />");
ret += tr("It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles.<br />");
ret += tr("The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.");
ret += "</p>";
ret += "<p>";
ret += tr("Strawberry is free software: you can redistribute it and/or modify<br />");
ret += tr("it under the terms of the GNU General Public License as published by<br />");
ret += tr("the Free Software Foundation, either version 3 of the License, or<br />");
ret += tr("(at your option) any later version.<br />");
ret += "<br />";
ret += tr("Strawberry is distributed in the hope that it will be useful,<br />");
ret += tr("but WITHOUT ANY WARRANTY; without even the implied warranty of<br />");
ret += tr("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />");
ret += tr("GNU General Public License for more details.<br />");
ret += "<br />";
ret += tr("You should have received a copy of the GNU General Public License<br />");
ret += tr("along with Strawberry. If not, see <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses/</a>.");
ret += "</p>";
return ret;
@ -130,25 +129,25 @@ QString About::ContributorsHtml() const {
QString ret;
ret += QString("<p><b>Strawberry Authors</b>");
ret += tr("<p><b>Strawberry Authors</b>");
for (const Person &person : strawberry_authors_) {
ret += "<br />" + PersonToHtml(person);
}
ret += QString("</p>");
ret += "</p>";
ret += QString("<p><b>Clementine Authors</b>");
ret += tr("<p><b>Clementine Authors</b>");
for (const Person &person : clementine_authors_) {
ret += "<br />" + PersonToHtml(person);
}
ret += QString("</p>");
ret += "</p>";
ret += QString("<p><b>Clementine Contributors</b>");
ret += tr("<p><b>Clementine Contributors</b>");
for (const Person &person : constributors_) {
ret += "<br />" + PersonToHtml(person);
}
ret += QString("</p>");
ret += "</p>";
ret += QString("<p>Thanks to all the Amarok and Clementine contributors.</p>");
ret += tr("<p>Thanks to all the Amarok and Clementine contributors.</p>");
return ret;
}

View File

@ -899,7 +899,7 @@ void EditTagDialog::SongSaveComplete(TagReaderReply *reply, const QString filena
pending_--;
if (!reply->message().save_file_response().success()) {
QString message = QString("An error occurred writing metadata to '%1'").arg(filename);
QString message = tr("An error occurred writing metadata to '%1'").arg(filename);
emit Error(message);
}
else if (song.directory_id() != -1) {

View File

@ -17,7 +17,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Clementine. If not, see <http://www.gnu.org/licenses/>.
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/

View File

@ -17,7 +17,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Clementine. If not, see <http://www.gnu.org/licenses/>.
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/

View File

@ -141,7 +141,7 @@ InternetSearchView::InternetSearchView(Application *app, InternetSearch *engine,
QMenu *settings_menu = new QMenu(this);
settings_menu->addActions(group_by_actions_->actions());
settings_menu->addSeparator();
settings_menu->addAction(IconLoader::Load("configure"), QString("Configure %1...").arg(Song::TextForSource(engine->source())), this, SLOT(OpenSettingsDialog()));
settings_menu->addAction(IconLoader::Load("configure"), tr("Configure %1...").arg(Song::TextForSource(engine->source())), this, SLOT(OpenSettingsDialog()));
ui_->settings->setMenu(settings_menu);
connect(ui_->radiobutton_search_artists, SIGNAL(clicked(bool)), SLOT(SearchArtistsClicked(bool)));
@ -430,7 +430,7 @@ bool InternetSearchView::ResultsContextMenuEvent(QContextMenuEvent *event) {
context_menu_->addSeparator();
context_menu_->addMenu(tr("Group by"))->addActions(group_by_actions_->actions());
context_menu_->addAction(IconLoader::Load("configure"), QString("Configure %1...").arg(Song::TextForSource(engine_->source())), this, SLOT(OpenSettingsDialog()));
context_menu_->addAction(IconLoader::Load("configure"), tr("Configure %1...").arg(Song::TextForSource(engine_->source())), this, SLOT(OpenSettingsDialog()));
const bool enable_context_actions = ui_->results->selectionModel() && ui_->results->selectionModel()->hasSelection();

View File

@ -51,11 +51,13 @@
#include <QApplication>
#include <QCoreApplication>
#include <QStandardPaths>
#include <QLibraryInfo>
#include <QFileDevice>
#include <QIODevice>
#include <QByteArray>
#include <QNetworkProxy>
#include <QFile>
#include <QDir>
#include <QString>
#include <QImage>
#include <QSettings>
@ -64,6 +66,9 @@
#ifdef HAVE_DBUS
# include <QDBusArgument>
#endif
#ifdef HAVE_TRANSLATIONS
# include <QTranslator>
#endif
#include "main.h"
@ -84,6 +89,10 @@
#include "core/application.h"
#include "core/networkproxyfactory.h"
#include "core/scangiomodulepath.h"
#ifdef HAVE_TRANSLATIONS
# include "core/potranslator.h"
#endif
#include "settings/behavioursettingspage.h"
#include "widgets/osd.h"
@ -206,11 +215,31 @@ int main(int argc, char* argv[]) {
// Resources
Q_INIT_RESOURCE(data);
Q_INIT_RESOURCE(icons);
#ifdef HAVE_TRANSLATIONS
Q_INIT_RESOURCE(translations);
#endif
#ifdef DEBUG
QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
#endif
#ifdef HAVE_TRANSLATIONS
QString override_language = options.language();
if (override_language.isEmpty()) {
QSettings s;
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
override_language = s.value("language").toString();
s.endGroup();
}
const QString language = override_language.isEmpty() ? Utilities::SystemLanguageName() : override_language;
Utilities::LoadTranslation("qt", QLibraryInfo::location(QLibraryInfo::TranslationsPath), language);
Utilities::LoadTranslation("strawberry", ":/translations", language);
Utilities::LoadTranslation("strawberry", a.applicationDirPath(), language);
Utilities::LoadTranslation("strawberry", QDir::currentPath(), language);
#endif
Application app;
// Network proxy

View File

@ -55,7 +55,7 @@
</size>
</property>
<property name="shortcut">
<string>Ctrl+</string>
<string>Ctrl+Up</string>
</property>
</widget>
</item>
@ -74,7 +74,7 @@
</size>
</property>
<property name="shortcut">
<string>Ctrl+</string>
<string>Ctrl+Down</string>
</property>
</widget>
</item>

View File

@ -141,7 +141,7 @@ void ListenBrainzScrobbler::Authenticate() {
bool result = QDesktopServices::openUrl(url);
if (!result) {
QMessageBox messagebox(QMessageBox::Information, "ListenBrainz Authentication", QString("Please open this URL in your browser:<br /><a href=\"%1\">%1</a>").arg(url.toString()), QMessageBox::Ok);
QMessageBox messagebox(QMessageBox::Information, tr("ListenBrainz Authentication"), tr("Please open this URL in your browser:<br /><a href=\"%1\">%1</a>").arg(url.toString()), QMessageBox::Ok);
messagebox.setTextFormat(Qt::RichText);
messagebox.exec();
}

View File

@ -132,7 +132,7 @@ void ScrobblingAPI20::Authenticate() {
url_query.addQueryItem("cb", redirect_url.toString());
url.setQuery(url_query);
QMessageBox messagebox(QMessageBox::Information, QString("%1 Scrobbler Authentication").arg(name_), QString("Open URL in web browser?<br /><a href=\"%1\">%1</a><br />Press \"Save\" to copy the URL to clipboard and manually open it in a web browser.").arg(url.toString()), QMessageBox::Open|QMessageBox::Save|QMessageBox::Cancel);
QMessageBox messagebox(QMessageBox::Information, tr("%1 Scrobbler Authentication").arg(name_), tr("Open URL in web browser?<br /><a href=\"%1\">%1</a><br />Press \"Save\" to copy the URL to clipboard and manually open it in a web browser.").arg(url.toString()), QMessageBox::Open|QMessageBox::Save|QMessageBox::Cancel);
messagebox.setTextFormat(Qt::RichText);
int result = messagebox.exec();
switch (result) {
@ -141,7 +141,7 @@ void ScrobblingAPI20::Authenticate() {
if (openurl_result) {
break;
}
QMessageBox messagebox_error(QMessageBox::Warning, QString("%1 Scrobbler Authentication").arg(name_), QString("Could not open URL. Please open this URL in your browser:<br /><a href=\"%1\">%1</a>").arg(url.toString()), QMessageBox::Ok);
QMessageBox messagebox_error(QMessageBox::Warning, tr("%1 Scrobbler Authentication").arg(name_), tr("Could not open URL. Please open this URL in your browser:<br /><a href=\"%1\">%1</a>").arg(url.toString()), QMessageBox::Ok);
messagebox_error.setTextFormat(Qt::RichText);
messagebox_error.exec();
}
@ -149,7 +149,7 @@ void ScrobblingAPI20::Authenticate() {
QApplication::clipboard()->setText(url.toString());
break;
case QMessageBox::Cancel:
AuthError("Authentication was cancelled.");
AuthError(tr("Authentication was cancelled."));
break;
default:
break;
@ -436,7 +436,7 @@ void ScrobblingAPI20::Scrobble(const Song &song) {
if (app_->scrobbler()->IsOffline()) return;
if (!IsAuthenticated()) {
emit ErrorMessage(QString("Scrobbler %1 is not authenticated!").arg(name_));
emit ErrorMessage(tr("Scrobbler %1 is not authenticated!").arg(name_));
return;
}

View File

@ -21,6 +21,10 @@
#include "config.h"
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QDir>
#include <QLocale>
#include <QSettings>
#include <QSystemTrayIcon>
#include <QCheckBox>
@ -37,6 +41,14 @@ class SettingsDialog;
const char *BehaviourSettingsPage::kSettingsGroup = "Behaviour";
#ifdef HAVE_TRANSLATIONS
namespace {
bool LocaleAwareCompare(const QString &a, const QString &b) {
return a.localeAwareCompare(b) < 0;
}
} // namespace
#endif
BehaviourSettingsPage::BehaviourSettingsPage(SettingsDialog *dialog) : SettingsPage(dialog), ui_(new Ui_BehaviourSettingsPage) {
ui_->setupUi(this);
@ -71,6 +83,43 @@ BehaviourSettingsPage::BehaviourSettingsPage(SettingsDialog *dialog) : SettingsP
ui_->combobox_menuplaymode->setItemData(1, MainWindow::PlayBehaviour_IfStopped);
ui_->combobox_menuplaymode->setItemData(2, MainWindow::PlayBehaviour_Always);
#ifdef HAVE_TRANSLATIONS
// Populate the language combo box. We do this by looking at all the compiled in translations.
QDir dir(":/translations/");
QStringList codes(dir.entryList(QStringList() << "*.qm"));
QRegExp lang_re("^strawberry_(.*).qm$");
for (const QString &filename : codes) {
// The regex captures the "ru" from "strawberry_ru.qm"
if (!lang_re.exactMatch(filename)) continue;
QString code = lang_re.cap(1);
QString lookup_code = QString(code)
.replace("@latin", "_Latn")
.replace("_CN", "_Hans_CN")
.replace("_TW", "_Hant_TW");
QString language_name = QLocale::languageToString(QLocale(lookup_code).language());
QString native_name = QLocale(lookup_code).nativeLanguageName();
if (!native_name.isEmpty()) {
language_name = native_name;
}
QString name = QString("%1 (%2)").arg(language_name, code);
language_map_[name] = code;
}
language_map_["English (en)"] = "en";
// Sort the names and show them in the UI
QStringList names = language_map_.keys();
std::stable_sort(names.begin(), names.end(), LocaleAwareCompare);
ui_->combobox_language->addItems(names);
#else
ui_->groupbox_language->setEnabled(false);
ui_->groupbox_language->setVisible(false);
#endif
}
BehaviourSettingsPage::~BehaviourSettingsPage() {
@ -114,6 +163,12 @@ void BehaviourSettingsPage::Load() {
ui_->spinbox_seekstepsec->setValue(s.value("seek_step_sec", 10).toInt());
QString name = language_map_.key(s.value("language").toString());
if (name.isEmpty())
ui_->combobox_language->setCurrentIndex(0);
else
ui_->combobox_language->setCurrentIndex(ui_->combobox_language->findText(name));
s.endGroup();
}
@ -141,6 +196,9 @@ void BehaviourSettingsPage::Save() {
s.setValue("doubleclick_playmode", doubleclick_playmode);
s.setValue("menu_playmode", menu_playmode);
s.setValue("seek_step_sec", ui_->spinbox_seekstepsec->value());
s.setValue("language", language_map_.contains(ui_->combobox_language->currentText()) ? language_map_[ui_->combobox_language->currentText()] : QString());
s.endGroup();
}

View File

@ -26,6 +26,7 @@
#include <stdbool.h>
#include <QObject>
#include <QMap>
#include <QString>
#include "settingspage.h"
@ -49,6 +50,7 @@ private slots:
private:
Ui_BehaviourSettingsPage *ui_;
QMap<QString, QString> language_map_;
};

View File

@ -101,6 +101,38 @@
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupbox_language">
<property name="title">
<string>Language</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<widget class="QComboBox" name="combobox_language">
<item>
<property name="text">
<string>Use the system default</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_language">
<property name="text">
<string>You will need to restart Strawberry if you change the language.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_1">
<property name="title">
@ -243,7 +275,7 @@
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>

View File

@ -237,7 +237,7 @@ void GlobalShortcutsSettingsPage::OpenGnomeKeybindingProperties() {
if (!QProcess::startDetached("gnome-keybinding-properties")) {
if (!QProcess::startDetached("gnome-control-center", QStringList() << "keyboard")) {
QMessageBox::warning(this, "Error", QString("The \"%1\" command could not be started.").arg("gnome-keybinding-properties"));
QMessageBox::warning(this, "Error", tr("The \"%1\" command could not be started.").arg("gnome-keybinding-properties"));
}
}

View File

@ -148,7 +148,7 @@ void TidalService::SendLogin() {
void TidalService::SendLogin(const QString &username, const QString &password) {
if (search_id_ != 0) emit UpdateStatus("Authenticating...");
if (search_id_ != 0) emit UpdateStatus(tr("Authenticating..."));
login_sent_ = true;
login_attempts_++;
@ -471,7 +471,7 @@ int TidalService::Search(const QString &text, InternetSearch::SearchType type) {
void TidalService::StartSearch() {
if (username_.isEmpty() || password_.isEmpty()) {
emit SearchError(pending_search_id_, "Missing username and/or password.");
emit SearchError(pending_search_id_, tr("Missing username and/or password."));
next_pending_search_id_ = 1;
ShowConfig();
return;
@ -509,7 +509,7 @@ void TidalService::ClearSearch() {
void TidalService::SendSearch() {
emit UpdateStatus("Searching...");
emit UpdateStatus(tr("Searching..."));
switch (pending_search_type_) {
case InternetSearch::SearchType_Artists:
@ -582,7 +582,7 @@ void TidalService::ArtistsReceived(QNetworkReply *reply, int search_id) {
QJsonArray json_items = json_value.toArray();
if (json_items.isEmpty()) {
artist_search_ = false;
Error("No match.");
Error(tr("No match."));
return;
}
@ -610,7 +610,8 @@ void TidalService::ArtistsReceived(QNetworkReply *reply, int search_id) {
}
if (artist_albums_requested_ > 0) {
emit UpdateStatus(QString("Retrieving albums for %1 artist%2...").arg(artist_albums_requested_).arg(artist_albums_requested_ == 1 ? "" : "s"));
if (artist_albums_requested_ == 1) emit UpdateStatus(tr("Retrieving albums for %1 artist...").arg(artist_albums_requested_));
else emit UpdateStatus(tr("Retrieving albums for %1 artists...").arg(artist_albums_requested_));
emit ProgressSetMaximum(artist_albums_requested_);
emit UpdateProgress(0);
}
@ -802,7 +803,8 @@ void TidalService::AlbumsFinished(const int artist_id, const int offset_requeste
}
if (album_songs_requested_ > 0) {
emit UpdateStatus(QString("Retrieving songs for %1 album%2...").arg(album_songs_requested_).arg(album_songs_requested_ == 1 ? "" : "s"));
if (album_songs_requested_ == 1) emit UpdateStatus(tr("Retrieving songs for %1 album...").arg(album_songs_requested_));
else emit UpdateStatus(tr("Retrieving songs for %1 albums...").arg(album_songs_requested_));
emit ProgressSetMaximum(album_songs_requested_);
emit UpdateProgress(0);
}

8
src/translations/header Normal file
View File

@ -0,0 +1,8 @@
# Strawberry Music Player
#
#, fuzzy
msgid ""
msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"