From: Soeren Apel Date: Sun, 10 Nov 2019 19:45:58 +0000 (+0100) Subject: Implement translations X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=0466001be51e779b23aaebec1cc9361305c07be9;p=pulseview.git Implement translations --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3770f1e4..885d9189 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ pkg_check_modules(PKGDEPS REQUIRED ${PKGDEPS}) set(CMAKE_AUTOMOC TRUE) -find_package(Qt5 5.3 COMPONENTS Core Gui Widgets Svg REQUIRED) +find_package(Qt5 5.3 COMPONENTS Core Gui LinguistTools Widgets Svg REQUIRED) message(STATUS "Qt version: ${Qt5_VERSION}") @@ -422,6 +422,18 @@ endif() qt5_add_resources(pulseview_RESOURCES_RCC ${pulseview_RESOURCES}) +#=============================================================================== +#= Translations +#------------------------------------------------------------------------------- + +file(GLOB TS_FILES l10n/*.ts) +set_property(SOURCE ${TS_FILES} PROPERTY OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/l10n) + +qt5_add_translation(QM_FILES ${TS_FILES}) +qt5_create_translation(QM_FILES ${pulseview_SOURCES} ${TS_FILES}) + +qt5_add_resources(pulseview_RESOURCES_RCC translations.qrc) + #=============================================================================== #= Global Definitions #------------------------------------------------------------------------------- @@ -513,9 +525,9 @@ if(ANDROID) endif() if(ANDROID) - add_library(${PROJECT_NAME} SHARED ${pulseview_SOURCES} ${pulseview_RESOURCES_RCC}) + add_library(${PROJECT_NAME} SHARED ${pulseview_SOURCES} ${pulseview_RESOURCES_RCC} ${QM_FILES}) else() - add_executable(${PROJECT_NAME} ${pulseview_SOURCES} ${pulseview_RESOURCES_RCC}) + add_executable(${PROJECT_NAME} ${pulseview_SOURCES} ${pulseview_RESOURCES_RCC} ${QM_FILES}) endif() target_link_libraries(${PROJECT_NAME} ${PULSEVIEW_LINK_LIBS}) diff --git a/l10n/de.ts b/l10n/de.ts new file mode 100644 index 00000000..02585b35 --- /dev/null +++ b/l10n/de.ts @@ -0,0 +1,1403 @@ + + + + + QApplication + + Select a decoder to see its description here. + Wähle einen Dekoder, um dessen Beschreibung hier lesen zu können. + + + Session %1 + Analysesitzung %1 + + + + Querying config key %1 is not allowed + + + + + Querying config key %1 resulted in %2 + + + + + Unknown type supplied when attempting to query %1 + + + + + Error when scanning device driver '%1': %2 + + + + + QObject + + + Cancel + + + + + Scanning for %1... + + + + + Stack trace of previous crash: + + + + + Don't show this message again + + + + + When %1 last crashed, it created a stack trace. +A human-readable form has been saved to disk and was written to the log. You may access it from the settings dialog. + + + + + SubWindow + + <p align='right'>Tags: %1</p> + <p align='right'>Stichworte: %1</p> + + + + pv::MainWindow + + + PulseView + + + + + Decoder Selector + Protokolldekoder + + + + Session %1 + Analysesitzung %1 + + + + Create New Session + Neue Analysesitzung + + + + Start/Stop Acquisition + + + + + Settings + Einstellungen + + + + + + Confirmation + Bestätigung + + + + There is unsaved data. Close anyway? + Es gibt noch ungespeicherte Daten. Trotzdem beenden? + + + + Run + Starten + + + + Stop + Anhalten + + + + + This session contains unsaved data. Close it anyway? + Die Daten dieser Analysesitzung wurden nicht gespeichert. Trotzdem schließen? + + + + pv::Session + + + Failed to select device + + + + + Failed to open device + + + + + Error + + + + + Unexpected input format: %s + + + + + Failed to load + + + + + No active device set, can't start acquisition. + + + + + No channels enabled. + + + + + Out of memory, acquisition stopped. + + + + + Can't handle more than 64 logic channels. + + + + + pv::StoreSession + + + Can't save logic channel without data. + + + + + Can't save analog channel without data. + + + + + No channels enabled. + + + + + Can't save range without sample data. + + + + + + Error while saving: + + + + + pv::data::DecodeSignal + + + No decoders + + + + + There are no channels assigned to this decoder + + + + + One or more required channels have not been specified + + + + + No input data + + + + + Decoder reported an error + + + + + Failed to create decoder instance + + + + + pv::data::SignalBase + + + Signal average + + + + + 0.9V (for 1.8V CMOS) + + + + + 1.8V (for 3.3V CMOS) + + + + + 2.5V (for 5.0V CMOS) + + + + + 1.5V (for TTL) + + + + + Signal average +/- 15% + + + + + 0.3V/1.2V (for 1.8V CMOS) + + + + + 0.7V/2.5V (for 3.3V CMOS) + + + + + 1.3V/3.7V (for 5.0V CMOS) + + + + + 0.8V/2.0V (for TTL) + + + + + pv::dialogs::Connect + + + &Scan for devices using driver above + + + + + Connect to Device + + + + + Step 1: Choose the driver + + + + + &USB + + + + + Serial &Port + + + + + &TCP/IP + + + + + Protocol: + + + + + Step 2: Choose the interface + + + + + Step 3: Scan for devices + + + + + Step 4: Select the device + + + + + pv::dialogs::Settings + + + + General + + + + + Views + + + + + + Decoders + + + + + About + + + + + Logging + + + + + User interface theme + + + + + (You may need to restart PulseView for all UI elements to update) + + + + + System Default + + + + + Qt widget style + + + + + (Dark themes look best with the Fusion style) + + + + + Save session &setup along with .sr file + + + + + Trace View + + + + + Use colored trace &background + + + + + Constantly perform &zoom-to-fit during acquisition + + + + + Perform a zoom-to-&fit when acquisition stops + + + + + Show time zero at the trigger + + + + + Always keep &newest samples at the right edge during capture + + + + + Show data &sampling points + + + + + Fill high areas of logic signals + + + + + Color to fill high areas of logic signals with + + + + + Show analog minor grid in addition to div grid + + + + + Highlight mouse cursor using a vertical marker line + + + + + + + pixels + + + + + Maximum distance from edges before cursors snap to them + + + + + Color to fill cursor area with + + + + + None + + + + + Background + + + + + Dots + + + + + Conversion threshold display mode (analog traces only) + + + + + Default analog trace div height + + + + + Default logic trace height + + + + + Allow configuration of &initial signal state + + + + + Always show all &rows, even if no annotation is visible + + + + + Annotation export format + + + + + %s = sample range; %d: decoder name; %c: row name; %q: use quotations marks + + + + + %1: longest annotation text; %a: all annotation texts + + + + + %1<br /><a href="http://%2">%2</a> + + + + + GNU GPL, version 3 or later + + + + + Versions, libraries and features: + + + + + Firmware search paths: + + + + + Protocol decoder search paths: + + + + + Supported hardware drivers: + + + + + Supported input formats: + + + + + Supported output formats: + + + + + Supported protocol decoders: + + + + + Log level: + + + + + lines + + + + + Length of background buffer: + + + + + &Save to File + + + + + &Pop out + + + + + You selected a dark theme. +Should I set the user-adjustable colors to better suit your choice? + +Please keep in mind that PulseView may need a restart to display correctly. + + + + + You selected a bright theme. +Should I set the user-adjustable colors to better suit your choice? + +Please keep in mind that PulseView may need a restart to display correctly. + + + + + Save Log + + + + + Log Files (*.txt *.log);;All Files (*) + + + + + Success + + + + + Log saved to %1. + + + + + Error + + + + + File %1 could not be written to. + + + + + %1 Log + + + + + pv::dialogs::StoreProgress + + + Saving... + + + + + Cancel + + + + + Failed to save session. + + + + + pv::popups::Channels + + + + All + + + + + + Logic + + + + + + Analog + + + + + Named + + + + + Unnamed + + + + + Changing + + + + + Non-changing + + + + + Disable: + + + + + Enable: + + + + + pv::prop::Bool + + + + Querying config key %1 resulted in %2 + + + + + pv::prop::Double + + + + Querying config key %1 resulted in %2 + + + + + pv::prop::Enum + + + + Querying config key %1 resulted in %2 + + + + + pv::prop::Int + + + + Querying config key %1 resulted in %2 + + + + + pv::prop::String + + + + Querying config key %1 resulted in %2 + + + + + pv::subwindows::decoder_selector::DecoderCollectionModel + + + Decoder + + + + + Name + + + + + ID + + + + + All Decoders + + + + + pv::subwindows::decoder_selector::SubWindow + + + Select a decoder to see its description here. + Wähle einen Dekoder, um dessen Beschreibung hier lesen zu können. + + + + , %1 + + + + + <p align='right'>Tags: %1</p> + <p align='right'>Stichworte: %1</p> + + + + Protocol decoder <b>%1</b> requires input type <b>%2</b> which several decoders provide.<br>Choose which one to use:<br> + + + + + Choose Decoder + + + + + pv::toolbars::MainBar + + + New &View + + + + + &Open... + + + + + Restore Session Setu&p... + + + + + &Save As... + + + + + Save Selected &Range As... + + + + + Save Session Setu&p... + + + + + &Export + + + + + &Import + + + + + &Connect to Device... + + + + + Add protocol decoder + + + + + Configure Device + + + + + Configure Channels + + + + + Failed to get sample rate list: + + + + + Failed to get sample rate: + + + + + Failed to get sample limit list: + + + + + Failed to configure samplerate: + + + + + Failed to configure sample count: + + + + + Missing Cursors + + + + + You need to set the cursors before you can save the data enclosed by them to a session file (e.g. using the Show Cursors button). + + + + + Invalid Range + + + + + The cursors don't define a valid range of samples. + + + + + %1 files + + + + + + All Files + + + + + + Save File + + + + + Export %1 + + + + + %1 files + + + + + Import File + + + + + Import %1 + + + + + + Open File + + + + + sigrok Sessions (*.sr);;All Files (*) + + + + + + PulseView Session Setups (*.pvs);;All Files (*) + + + + + Total sampling time: %1 + + + + + pv::views::trace::AnalogSignal + + + Number of pos vertical divs + + + + + Number of neg vertical divs + + + + + pixels + + + + + Div height + + + + + V/div + + + + + Vertical resolution + + + + + Autoranging + + + + + none + + + + + to logic via threshold + + + + + to logic via schmitt-trigger + + + + + Conversion + + + + + Conversion threshold(s) + + + + + analog + + + + + converted + + + + + analog+converted + + + + + Show traces for + + + + + pv::views::trace::Cursor + + + Disable snapping + + + + + pv::views::trace::DecodeTrace + + + <p><i>No decoders in the stack</i></p> + + + + + <i>* Required channels</i> + + + + + Stack Decoder + + + + + Stack a higher-level decoder on top of this one + + + + + Delete + + + + + Resume decoding + + + + + Pause decoding + + + + + Copy annotation text to clipboard + + + + + Export all annotations + + + + + Export all annotations for this row + + + + + Export all annotations, starting here + + + + + Export annotations for this row, starting here + + + + + Export all annotations within cursor range + + + + + Export annotations for this row within cursor range + + + + + %1: +%2 + + + + + <b>%1</b> (%2) %3 + + + + + Export annotations + + + + + Text Files (*.txt);;All Files (*) + + + + + Error + + + + + File %1 could not be written to. + + + + + pv::views::trace::Flag + + + Text + + + + + Delete + + + + + Disable snapping + + + + + pv::views::trace::Header + + + Group + + + + + pv::views::trace::LogicSignal + + + No trigger + + + + + Trigger on rising edge + + + + + Trigger on high level + + + + + Trigger on falling edge + + + + + Trigger on low level + + + + + Trigger on rising or falling edge + + + + + pixels + + + + + Trace height + + + + + Trigger + + + + + pv::views::trace::Ruler + + + Create marker here + + + + + Set as zero point + + + + + Disable mouse hover marker + + + + + Enable mouse hover marker + + + + + pv::views::trace::Signal + + + Name + + + + + Disable + + + + + pv::views::trace::StandardBar + + + Zoom &In + + + + + Zoom &Out + + + + + Zoom to &Fit + + + + + Show &Cursors + + + + + Display last segment only + + + + + Display last complete segment only + + + + + Display a single segment + + + + + pv::views::trace::TimeMarker + + + Time + + + + + pv::views::trace::Trace + + + Create marker here + + + + + Color + + + + + Name + + + + + pv::views::trace::TraceGroup + + + Ungroup + + + + + pv::widgets::DecoderGroupBox + + + Show/hide this decoder trace + + + + + Delete this decoder trace + + + + + pv::widgets::DeviceToolButton + + + + <No Device> + + + + + pv::widgets::ExportMenu + + + Export %1... + + + + + pv::widgets::ImportMenu + + + Import %1... + + + + diff --git a/main.cpp b/main.cpp index 4bbddcc6..da5fffcd 100644 --- a/main.cpp +++ b/main.cpp @@ -279,8 +279,10 @@ int main(int argc, char *argv[]) // Prepare the global settings since logging needs them early on pv::GlobalSettings settings; + settings.add_change_handler(&a); // Only the application object can't register itself settings.save_internal_defaults(); settings.set_defaults_where_needed(); + settings.apply_language(); settings.apply_theme(); pv::logging.init(); diff --git a/pv/application.cpp b/pv/application.cpp index 5a6e28a1..e933f962 100644 --- a/pv/application.cpp +++ b/pv/application.cpp @@ -17,9 +17,6 @@ * along with this program; if not, see . */ -#include "application.hpp" -#include "config.h" - #include #include @@ -35,6 +32,10 @@ #include #endif +#include "application.hpp" +#include "config.h" +#include "globalsettings.hpp" + using std::cout; using std::endl; using std::exception; @@ -60,6 +61,34 @@ Application::Application(int &argc, char* argv[]) : setOrganizationDomain("sigrok.org"); } +void Application::switch_language(const QString& language) +{ + removeTranslator(&app_translator_); + removeTranslator(&qt_translator_); + + if ((language != "C") && (language != "en")) { + // Application translations + QString resource = ":/l10n/" + language +".qm"; + if (app_translator_.load(resource)) + installTranslator(&app_translator_); + else + qWarning() << "Translation resource" << resource << "not found"; + + // Qt translations + resource = ":/l10n/qtbase_" + language +".qm"; + if (qt_translator_.load(resource)) + installTranslator(&qt_translator_); + else + qWarning() << "Translation resource" << resource << "not found"; + } +} + +void Application::on_setting_changed(const QString &key, const QVariant &value) +{ + if (key == pv::GlobalSettings::Key_General_Language) + switch_language(value.toString()); +} + void Application::collect_version_info(shared_ptr context) { // Library versions and features diff --git a/pv/application.hpp b/pv/application.hpp index c618f80d..a653ab45 100644 --- a/pv/application.hpp +++ b/pv/application.hpp @@ -23,20 +23,26 @@ #include #include +#include #include +#include "globalsettings.hpp" + using std::shared_ptr; using std::pair; using std::vector; -class Application : public QApplication +class Application : public QApplication, public pv::GlobalSettingsInterface { Q_OBJECT public: Application(int &argc, char* argv[]); + void switch_language(const QString& language); + void on_setting_changed(const QString &key, const QVariant &value); + void collect_version_info(shared_ptr context); void print_version_info(); @@ -58,6 +64,8 @@ private: vector< pair > input_format_list_; vector< pair > output_format_list_; vector< pair > pd_list_; + + QTranslator app_translator_, qt_translator_; }; #endif // PULSEVIEW_PV_APPLICATION_HPP diff --git a/pv/globalsettings.cpp b/pv/globalsettings.cpp index f7df4802..1c23e04c 100644 --- a/pv/globalsettings.cpp +++ b/pv/globalsettings.cpp @@ -18,6 +18,7 @@ */ #include "globalsettings.hpp" +#include "application.hpp" #include #include @@ -42,6 +43,7 @@ const vector< pair > Themes { {"DarkStyle", ":/themes/darkstyle/darkstyle.qss"} }; +const QString GlobalSettings::Key_General_Language = "General_Language"; const QString GlobalSettings::Key_General_Theme = "General_Theme"; const QString GlobalSettings::Key_General_Style = "General_Style"; const QString GlobalSettings::Key_General_SaveWithSetup = "General_SaveWithSetup"; @@ -90,6 +92,14 @@ void GlobalSettings::save_internal_defaults() void GlobalSettings::set_defaults_where_needed() { + if (!contains(Key_General_Language)) { + // Determine and set default UI language + QString language = QLocale().uiLanguages().first(); // May return e.g. en-Latn-US + language = language.split("-").first(); + + setValue(Key_General_Language, language); + } + // Use no theme by default if (!contains(Key_General_Theme)) setValue(Key_General_Theme, 0); @@ -231,6 +241,12 @@ void GlobalSettings::apply_theme() QPixmapCache::clear(); } +void GlobalSettings::apply_language() +{ + Application* a = qobject_cast(QApplication::instance()); + a->switch_language(value(Key_General_Language).toString()); +} + void GlobalSettings::add_change_handler(GlobalSettingsInterface *cb) { callbacks_.push_back(cb); diff --git a/pv/globalsettings.hpp b/pv/globalsettings.hpp index 6902a097..56ca9632 100644 --- a/pv/globalsettings.hpp +++ b/pv/globalsettings.hpp @@ -51,6 +51,7 @@ class GlobalSettings : public QSettings Q_OBJECT public: + static const QString Key_General_Language; static const QString Key_General_Theme; static const QString Key_General_Style; static const QString Key_General_SaveWithSetup; @@ -92,6 +93,8 @@ public: static bool current_theme_is_dark(); void apply_theme(); + void apply_language(); + static void add_change_handler(GlobalSettingsInterface *cb); static void remove_change_handler(GlobalSettingsInterface *cb); diff --git a/pv/mainwindow.cpp b/pv/mainwindow.cpp index d7f5c31a..1fb46e13 100644 --- a/pv/mainwindow.cpp +++ b/pv/mainwindow.cpp @@ -40,6 +40,7 @@ #include "mainwindow.hpp" +#include "application.hpp" #include "devicemanager.hpp" #include "devices/hardwaredevice.hpp" #include "dialogs/settings.hpp" diff --git a/pv/subwindows/decoder_selector/subwindow.cpp b/pv/subwindows/decoder_selector/subwindow.cpp index 20603ed2..94ed6f4b 100644 --- a/pv/subwindows/decoder_selector/subwindow.cpp +++ b/pv/subwindows/decoder_selector/subwindow.cpp @@ -33,6 +33,7 @@ #include "pv/subwindows/decoder_selector/subwindow.hpp" #include +#include "subwindow.hpp" // Required only for lupdate since above include isn't recognized #define DECODERS_HAVE_TAGS \ ((SRD_PACKAGE_VERSION_MAJOR > 0) || \ @@ -46,7 +47,7 @@ namespace decoder_selector { const char *initial_notice = QT_TRANSLATE_NOOP("pv::subwindows::decoder_selector::SubWindow", - "Select a decoder to see its description here."); // clazy:exclude=non-pod-global-static + "Select a decoder to see its description here."); // clazy:exclude=non-pod-global-static const int min_width_margin = 75; diff --git a/translations.qrc b/translations.qrc new file mode 100644 index 00000000..103fa359 --- /dev/null +++ b/translations.qrc @@ -0,0 +1,5 @@ + + + l10n/de.qm + +