From 791f9cbccbef3fcbf5433329a313e7b4c28bbaab Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 4 Aug 2019 16:00:55 +0200 Subject: [PATCH 01/15] [packagechooser] Read packages model from config - add key *items* which will be used to fill up the model for software products. TODO: needs translation support --- .../packagechooser/PackageChooserViewStep.cpp | 55 ++++++++++++++++++- .../packagechooser/PackageChooserViewStep.h | 1 + .../packagechooser/packagechooser.conf | 35 ++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/modules/packagechooser/PackageChooserViewStep.cpp b/src/modules/packagechooser/PackageChooserViewStep.cpp index 8515d03a9..4d9ab4f5f 100644 --- a/src/modules/packagechooser/PackageChooserViewStep.cpp +++ b/src/modules/packagechooser/PackageChooserViewStep.cpp @@ -177,6 +177,15 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap m_id = moduleInstanceKey().split( '@' ).last(); } + bool first_time = !m_model; + + ok = false; + QVariantMap items = CalamaresUtils::getSubMap( configurationMap, "items", ok ); + if ( ok ) + { + fillModel( items ); + } + // TODO: replace this hard-coded model if ( !m_model ) { @@ -192,12 +201,54 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap m_model->addPackage( PackageItem { "kde", "kde", "Plasma", "Plasma Desktop", ":/images/kde.png" } ); m_model->addPackage( PackageItem { "gnome", "gnome", "GNOME", "GNU Networked Object Modeling Environment Desktop", ":/images/gnome.png" } ); + } + if ( first_time && m_widget && m_model ) + { + hookupModel(); + } +} - if ( m_widget ) +void +PackageChooserViewStep::fillModel( const QVariantMap& items ) +{ + if ( !m_model ) + { + m_model = new PackageListModel( nullptr ); + } + + cDebug() << "Loading PackageChooser model items from config"; + for ( auto item_it = items.constKeyValueBegin(); item_it != items.constKeyValueEnd(); ++item_it ) + { + QString id = ( *item_it ).first; + + QVariantMap item_map = ( *item_it ).second.toMap(); + if ( item_map.isEmpty() ) { - hookupModel(); + cWarning() << "PackageChooser item" << id << "is not valid."; + continue; } + + QString package = CalamaresUtils::getString( item_map, "package" ); + QString name = CalamaresUtils::getString( item_map, "name" ); + QString description = CalamaresUtils::getString( item_map, "description" ); + QString screenshot = CalamaresUtils::getString( item_map, "screenshot" ); + + if ( name.isEmpty() ) + { + cWarning() << "PackageChooser item" << id << "has an empty name."; + continue; + } + if ( description.isEmpty() ) + { + description = tr( "No description provided." ); + } + if ( screenshot.isEmpty() ) + { + screenshot = QStringLiteral( ":/images/no-selection.png" ); + } + + m_model->addPackage( PackageItem { id, package, name, description, screenshot } ); } } diff --git a/src/modules/packagechooser/PackageChooserViewStep.h b/src/modules/packagechooser/PackageChooserViewStep.h index 55ed2d4d5..4d5cc346f 100644 --- a/src/modules/packagechooser/PackageChooserViewStep.h +++ b/src/modules/packagechooser/PackageChooserViewStep.h @@ -56,6 +56,7 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ) override; private: + void fillModel( const QVariantMap& items ); void hookupModel(); PackageChooserPage* m_widget; diff --git a/src/modules/packagechooser/packagechooser.conf b/src/modules/packagechooser/packagechooser.conf index b4e48c995..f4bab476c 100644 --- a/src/modules/packagechooser/packagechooser.conf +++ b/src/modules/packagechooser/packagechooser.conf @@ -19,3 +19,38 @@ # or "optionalmultiple", "requiredmultiple" (for zero-or-more # or one-or-more). mode: required + +# Items to display in the chooser. In general, this should be a +# pretty short list to avoid overwhelming the UI. +# +# Each item has a key, which is used as its ID (used in setting +# the value of *packagechooser_*). The following fields +# are mandatory: +# +# - *package* Package name for the product. While mandatory, this is +# not actually used anywhere. +# - *name* Human-readable, but untranslated, name of the product. +# - *description* Human-readable, but untranslated, description. +# - *screenshot* Path to a single screenshot of the product. May be +# a filesystem path or a QRC path (e.g. ":/images/no-selection.png"). +# +# Use the empty string "" as ID / key for the "no selection" item if +# you want to customize the display of that item as well. +items: + "": + package: "" + name: "No Desktop" + description: "Please pick a desktop environment from the list. If you don't want to install a desktop, that's fine, your system will start up in text-only mode and you can install a desktop environment later." + screenshot: ":/images/no-selection.png" + kde: + package: kde + name: Plasma Desktop + description: "KDE Plasma Desktop, simple by default, a clean work area for real-world usage which intends to stay out of your way. Plasma is powerful when needed, enabling the user to create the workflow that makes them more effective to complete their tasks." + screenshot: ":/images/kde.png" + gnome: + package: gnome + name: GNOME + description: GNU Networked Object Modeling Environment Desktop + screenshot: ":/images/gnome.png" + + From 9a52430e74d8b8b9b763725e01f150d97b378c87 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 4 Aug 2019 20:04:32 +0200 Subject: [PATCH 02/15] [packagechooser] Too many 'o's in test name --- src/modules/packagechooser/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/packagechooser/CMakeLists.txt b/src/modules/packagechooser/CMakeLists.txt index 483092800..4663ccce7 100644 --- a/src/modules/packagechooser/CMakeLists.txt +++ b/src/modules/packagechooser/CMakeLists.txt @@ -20,11 +20,11 @@ if( ECM_FOUND AND BUILD_TESTING ) ecm_add_test( Tests.cpp TEST_NAME - packagechooosertest + packagechoosertest LINK_LIBRARIES ${CALAMARES_LIBRARIES} Qt5::Core Qt5::Test ) - calamares_automoc( packagechooosertest) + calamares_automoc( packagechoosertest) endif() From b16354133da0f5873f7eee25d1e1aeec297d2483 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 4 Aug 2019 20:19:56 +0200 Subject: [PATCH 03/15] [packagechooser] Switch to a list form - Using id's as keys in a map orders them indeterminately -- in practice, alphabetically by key. Switch to a list form so that the products stick to the order they have in the config file (which means distro's can list "preferred" versions at top). --- .../packagechooser/PackageChooserViewStep.cpp | 32 +++++++++------ .../packagechooser/PackageChooserViewStep.h | 2 +- .../packagechooser/packagechooser.conf | 40 ++++++++++--------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/modules/packagechooser/PackageChooserViewStep.cpp b/src/modules/packagechooser/PackageChooserViewStep.cpp index 4d9ab4f5f..4476eb9e6 100644 --- a/src/modules/packagechooser/PackageChooserViewStep.cpp +++ b/src/modules/packagechooser/PackageChooserViewStep.cpp @@ -178,12 +178,9 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap } bool first_time = !m_model; - - ok = false; - QVariantMap items = CalamaresUtils::getSubMap( configurationMap, "items", ok ); - if ( ok ) + if ( configurationMap.contains( "items" ) ) { - fillModel( items ); + fillModel( configurationMap.value( "items" ).toList() ); } // TODO: replace this hard-coded model @@ -210,31 +207,42 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap } void -PackageChooserViewStep::fillModel( const QVariantMap& items ) +PackageChooserViewStep::fillModel( const QVariantList& items ) { if ( !m_model ) { m_model = new PackageListModel( nullptr ); } - cDebug() << "Loading PackageChooser model items from config"; - for ( auto item_it = items.constKeyValueBegin(); item_it != items.constKeyValueEnd(); ++item_it ) + if ( items.isEmpty() ) { - QString id = ( *item_it ).first; + cWarning() << "No *items* for PackageChooser module."; + return; + } - QVariantMap item_map = ( *item_it ).second.toMap(); + cDebug() << "Loading PackageChooser model items from config"; + int item_index = 0; + for ( const auto& item_it : items ) + { + ++item_index; + QVariantMap item_map = item_it.toMap(); if ( item_map.isEmpty() ) { - cWarning() << "PackageChooser item" << id << "is not valid."; + cWarning() << "PackageChooser entry" << item_index << "is not valid."; continue; } + QString id = CalamaresUtils::getString( item_map, "id" ); QString package = CalamaresUtils::getString( item_map, "package" ); QString name = CalamaresUtils::getString( item_map, "name" ); QString description = CalamaresUtils::getString( item_map, "description" ); QString screenshot = CalamaresUtils::getString( item_map, "screenshot" ); - if ( name.isEmpty() ) + if ( name.isEmpty() && id.isEmpty() ) + { + name = tr( "No product" ); + } + else if ( name.isEmpty() ) { cWarning() << "PackageChooser item" << id << "has an empty name."; continue; diff --git a/src/modules/packagechooser/PackageChooserViewStep.h b/src/modules/packagechooser/PackageChooserViewStep.h index 4d5cc346f..e3ffc1d5b 100644 --- a/src/modules/packagechooser/PackageChooserViewStep.h +++ b/src/modules/packagechooser/PackageChooserViewStep.h @@ -56,7 +56,7 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ) override; private: - void fillModel( const QVariantMap& items ); + void fillModel( const QVariantList& items ); void hookupModel(); PackageChooserPage* m_widget; diff --git a/src/modules/packagechooser/packagechooser.conf b/src/modules/packagechooser/packagechooser.conf index f4bab476c..391e1f325 100644 --- a/src/modules/packagechooser/packagechooser.conf +++ b/src/modules/packagechooser/packagechooser.conf @@ -21,12 +21,16 @@ mode: required # Items to display in the chooser. In general, this should be a -# pretty short list to avoid overwhelming the UI. +# pretty short list to avoid overwhelming the UI. This is a list +# of objects, and the items are displayed in list order. # -# Each item has a key, which is used as its ID (used in setting -# the value of *packagechooser_*). The following fields +# Each item has an id, which is used in setting # the value of +# *packagechooser_*). The following fields # are mandatory: # +# - *id* ID for the product. The ID "" is special, and is used for +# "no package selected". Only include this if the mode allows +# selecting none. # - *package* Package name for the product. While mandatory, this is # not actually used anywhere. # - *name* Human-readable, but untranslated, name of the product. @@ -37,20 +41,20 @@ mode: required # Use the empty string "" as ID / key for the "no selection" item if # you want to customize the display of that item as well. items: - "": - package: "" - name: "No Desktop" - description: "Please pick a desktop environment from the list. If you don't want to install a desktop, that's fine, your system will start up in text-only mode and you can install a desktop environment later." - screenshot: ":/images/no-selection.png" - kde: - package: kde - name: Plasma Desktop - description: "KDE Plasma Desktop, simple by default, a clean work area for real-world usage which intends to stay out of your way. Plasma is powerful when needed, enabling the user to create the workflow that makes them more effective to complete their tasks." - screenshot: ":/images/kde.png" - gnome: - package: gnome - name: GNOME - description: GNU Networked Object Modeling Environment Desktop - screenshot: ":/images/gnome.png" + - id: "" + package: "" + name: "No Desktop" + description: "Please pick a desktop environment from the list. If you don't want to install a desktop, that's fine, your system will start up in text-only mode and you can install a desktop environment later." + screenshot: ":/images/no-selection.png" + - id: kde + package: kde + name: Plasma Desktop + description: "KDE Plasma Desktop, DERP" + screenshot: ":/images/kde.png" + - id: gnome + package: gnome + name: GNOME + description: GNU Networked Object Modeling Environment Desktop + screenshot: ":/images/gnome.png" From 8ea4091c7b6d14e52367ef2f8bda8dfee2ec23b5 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 4 Aug 2019 22:56:41 +0200 Subject: [PATCH 04/15] [libcalamares] Add a TranslatedString class to locale/ - While QObject::tr and gettext give us translations **most** of the time via the translation mechanism, we sometimes have strings embedded in configuration files that need to be shown to people as well. Follow the .desktop style in handling this. - A key's value **might** be translated; use `key[lang]` for the translation into one of the languages that Calamares understands. Code that expects a translated (human-readable) string in a configuration file can use TranslatedString to collect all the translations of a given key, so that it displays the right string from the configuration when needed. --- src/libcalamares/CMakeLists.txt | 1 + .../locale/TranslatableConfiguration.cpp | 67 +++++++++++++++++++ .../locale/TranslatableConfiguration.h | 54 +++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 src/libcalamares/locale/TranslatableConfiguration.cpp create mode 100644 src/libcalamares/locale/TranslatableConfiguration.h diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 19bcc921d..0aca79233 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -34,6 +34,7 @@ set( libSources locale/Label.cpp locale/LabelModel.cpp locale/Lookup.cpp + locale/TranslatableConfiguration.cpp # Partition service partition/PartitionSize.cpp diff --git a/src/libcalamares/locale/TranslatableConfiguration.cpp b/src/libcalamares/locale/TranslatableConfiguration.cpp new file mode 100644 index 000000000..6d4684121 --- /dev/null +++ b/src/libcalamares/locale/TranslatableConfiguration.cpp @@ -0,0 +1,67 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares 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. + * + * Calamares 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 Calamares. If not, see . + */ + +#include "TranslatableConfiguration.h" + +#include "LabelModel.h" + +#include "utils/Logger.h" +#include "utils/Variant.h" + +#include +#include + +namespace CalamaresUtils +{ +namespace Locale +{ +TranslatedString::TranslatedString(const QString& string) +{ + m_strings[QString()]=string; +} +TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) +{ + // Get the un-decorated value for the key + QString value = CalamaresUtils::getString( map, key ); + if ( value.isEmpty() ) + { + value = key; + } + m_strings[QString()] = value; + + for ( auto it = m_strings.constKeyValueBegin(); it != m_strings.constKeyValueEnd(); ++it ) + { + QString subkey = (*it).first; + if ( subkey == key ) + { + // Already obtained, above + } + else if ( subkey.startsWith( key ) ) + { + QRegularExpressionMatch match; + if ( subkey.indexOf( QRegularExpression("\\[([a-zA-Z_@]*)\\]"), 0, &match ) > 0 ) + { + QString language = match.captured(1); + cDebug() << "Found translation" << key << '[' << language << ']'; + } + } + } +} + +} // namespace Locale +} // namespace CalamaresUtils diff --git a/src/libcalamares/locale/TranslatableConfiguration.h b/src/libcalamares/locale/TranslatableConfiguration.h new file mode 100644 index 000000000..8cc02fadd --- /dev/null +++ b/src/libcalamares/locale/TranslatableConfiguration.h @@ -0,0 +1,54 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares 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. + * + * Calamares 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 Calamares. If not, see . + */ + +#ifndef LOCALE_TRANSLATABLECONFIGURATION_H +#define LOCALE_TRANSLATABLECONFIGURATION_H + +#include "DllMacro.h" + +#include +#include +#include + +namespace CalamaresUtils +{ +namespace Locale +{ + /** @brief A human-readable string from a configuration file + * + * The configuration files can contain human-readable strings, + * but those need their own translations and are not supported + * by QObject::tr or anything else. + */ + class DLLEXPORT TranslatedString + { + public: + /** @brief Get all the translations connected to @p key + */ + TranslatedString( const QVariantMap& map, const QString& key ); + /** @brief Not-actually-translated string. + */ + TranslatedString( const QString& string ); + private: + // Maps locale name to human-readable string, "" is English + QMap< QString, QString > m_strings; + }; +} // namespace Locale +} // namespace CalamaresUtils + +#endif From 18e2f2ae527f6c83a1bb33d0e046bc0556e33a4f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 5 Aug 2019 17:57:32 +0200 Subject: [PATCH 05/15] [libcalamares] Add tests for new TranslatedString - Test that construction works as expected - Add count() method to TranslatedString for testing purposes. --- src/libcalamares/locale/Tests.cpp | 47 +++++++++++++++++++ src/libcalamares/locale/Tests.h | 3 ++ .../locale/TranslatableConfiguration.cpp | 5 +- .../locale/TranslatableConfiguration.h | 3 ++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index 9e2071a31..a87de8a98 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -19,7 +19,10 @@ #include "Tests.h" #include "locale/LabelModel.h" +#include "locale/TranslatableConfiguration.h" + #include "utils/Logger.h" +#include "CalamaresVersion.h" #include @@ -81,3 +84,47 @@ LocaleTests::testEsperanto() QCOMPARE( QLocale( "eo" ).language(), QLocale::C ); } + +static const QStringList& +someLanguages() +{ + static QStringList languages{ "nl", "de", "da", "nb", "sr@latin", "ar", "ru" }; + return languages; + } + + + void LocaleTests::testTranslatableLanguages() +{ + QStringList availableLanguages = QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';' ); + cDebug() << "Translation languages:" << availableLanguages; + for ( const auto& language: someLanguages() ) + { + // Could be QVERIFY, but then we don't see what language code fails + QCOMPARE( availableLanguages.contains( language ) ? language : QString(), language ); + } +} + +void LocaleTests::testTranslatableConfig1() +{ + CalamaresUtils::Locale::TranslatedString ts1( "Hello" ); + QCOMPARE( ts1.count(), 1 ); + + QVariantMap map; + map.insert( "description", "description (no language)" ); + CalamaresUtils::Locale::TranslatedString ts2(map, "description"); + QCOMPARE( ts2.count(), 1 ); +} + +void LocaleTests::testTranslatableConfig2() +{ + QVariantMap map; + + for ( const auto& language: someLanguages() ) + { + map.insert( QString("description[%1]").arg(language), QString("description (language %1)").arg(language) ); + } + + CalamaresUtils::Locale::TranslatedString s(map, "description"); + // The +1 is because "" is always also inserted + QCOMPARE( s.count(), someLanguages().count()+1 ); +} diff --git a/src/libcalamares/locale/Tests.h b/src/libcalamares/locale/Tests.h index be712388f..c6949f3e4 100644 --- a/src/libcalamares/locale/Tests.h +++ b/src/libcalamares/locale/Tests.h @@ -33,6 +33,9 @@ private Q_SLOTS: void testLanguageModelCount(); void testEsperanto(); + void testTranslatableLanguages(); + void testTranslatableConfig1(); + void testTranslatableConfig2(); }; #endif diff --git a/src/libcalamares/locale/TranslatableConfiguration.cpp b/src/libcalamares/locale/TranslatableConfiguration.cpp index 6d4684121..d6c078303 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.cpp +++ b/src/libcalamares/locale/TranslatableConfiguration.cpp @@ -44,7 +44,7 @@ TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) } m_strings[QString()] = value; - for ( auto it = m_strings.constKeyValueBegin(); it != m_strings.constKeyValueEnd(); ++it ) + for ( auto it = map.constKeyValueBegin(); it != map.constKeyValueEnd(); ++it ) { QString subkey = (*it).first; if ( subkey == key ) @@ -53,11 +53,12 @@ TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) } else if ( subkey.startsWith( key ) ) { + cDebug() << "Checking" << subkey; QRegularExpressionMatch match; if ( subkey.indexOf( QRegularExpression("\\[([a-zA-Z_@]*)\\]"), 0, &match ) > 0 ) { QString language = match.captured(1); - cDebug() << "Found translation" << key << '[' << language << ']'; + m_strings[language] = (*it).second.toString(); } } } diff --git a/src/libcalamares/locale/TranslatableConfiguration.h b/src/libcalamares/locale/TranslatableConfiguration.h index 8cc02fadd..01bdf8ed6 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.h +++ b/src/libcalamares/locale/TranslatableConfiguration.h @@ -44,6 +44,9 @@ namespace Locale /** @brief Not-actually-translated string. */ TranslatedString( const QString& string ); + + int count() const { return m_strings.count(); } + private: // Maps locale name to human-readable string, "" is English QMap< QString, QString > m_strings; From 28293ef77a607d3b694e8d86b0dffbca9f0d1827 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 5 Aug 2019 23:30:51 +0200 Subject: [PATCH 06/15] [libcalamares] Expand tests of TranslatableString --- src/libcalamares/locale/Tests.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index a87de8a98..46b1df150 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -122,9 +122,17 @@ void LocaleTests::testTranslatableConfig2() for ( const auto& language: someLanguages() ) { map.insert( QString("description[%1]").arg(language), QString("description (language %1)").arg(language) ); + if ( language != "nl" ) + { + map.insert( QString("name[%1]").arg(language), QString("name (language %1)").arg(language) ); + } } - CalamaresUtils::Locale::TranslatedString s(map, "description"); + CalamaresUtils::Locale::TranslatedString ts1(map, "description"); // The +1 is because "" is always also inserted - QCOMPARE( s.count(), someLanguages().count()+1 ); + QCOMPARE( ts1.count(), someLanguages().count()+1 ); + + CalamaresUtils::Locale::TranslatedString ts2(map, "name"); + // We skipped dutch this time + QCOMPARE( ts2.count(), someLanguages().count() ); } From e0edd1f3e2bc57f826acd9b9713110dacbd107be Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 5 Aug 2019 23:32:13 +0200 Subject: [PATCH 07/15] [libcalamares] Fix misleading comment, add accessor - the sort order is not English-at-the-top - add accessor for the locale ID. --- src/libcalamares/locale/Label.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcalamares/locale/Label.h b/src/libcalamares/locale/Label.h index ab3e80ad0..0fe61d909 100644 --- a/src/libcalamares/locale/Label.h +++ b/src/libcalamares/locale/Label.h @@ -58,7 +58,7 @@ public: /** @brief Define a sorting order. * - * English (@see isEnglish() -- it means en_US) is sorted at the top. + * Locales are sorted by their id, which means the ISO 2-letter code + country. */ bool operator<( const Label& other ) const { return m_localeId < other.m_localeId; } @@ -78,6 +78,7 @@ public: QLocale locale() const { return m_locale; } QString name() const { return m_locale.name(); } + QString id() const { return m_localeId; } /// @brief Convenience accessor to the language part of the locale QLocale::Language language() const { return m_locale.language(); } From 50d74c4eca3e919b9bd7f769d2381e3f4432ccc0 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 5 Aug 2019 23:37:25 +0200 Subject: [PATCH 08/15] [libcalamares] Add get() to the string - Look up the translation of the requested string with the current or a specific locale. This implementation is a stub. - Add tests for the getter. --- src/libcalamares/locale/Tests.cpp | 9 +++++++++ .../locale/TranslatableConfiguration.cpp | 13 ++++++++++++- src/libcalamares/locale/TranslatableConfiguration.h | 6 ++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index 46b1df150..1cfd733a0 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -109,10 +109,16 @@ void LocaleTests::testTranslatableConfig1() CalamaresUtils::Locale::TranslatedString ts1( "Hello" ); QCOMPARE( ts1.count(), 1 ); + QCOMPARE( ts1.get(), "Hello" ); + QCOMPARE( ts1.get( QLocale("nl")), "Hello" ); + QVariantMap map; map.insert( "description", "description (no language)" ); CalamaresUtils::Locale::TranslatedString ts2(map, "description"); QCOMPARE( ts2.count(), 1 ); + + QCOMPARE( ts2.get(), "description (no language)"); + QCOMPARE( ts2.get( QLocale( "nl" ) ), "description (no language)"); } void LocaleTests::testTranslatableConfig2() @@ -131,6 +137,9 @@ void LocaleTests::testTranslatableConfig2() CalamaresUtils::Locale::TranslatedString ts1(map, "description"); // The +1 is because "" is always also inserted QCOMPARE( ts1.count(), someLanguages().count()+1 ); + + QCOMPARE( ts1.get(), "description"); // it wasn't set + QCOMPARE( ts1.get( QLocale( "nl" ) ), "description (language nl)"); CalamaresUtils::Locale::TranslatedString ts2(map, "name"); // We skipped dutch this time diff --git a/src/libcalamares/locale/TranslatableConfiguration.cpp b/src/libcalamares/locale/TranslatableConfiguration.cpp index d6c078303..d7066a57c 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.cpp +++ b/src/libcalamares/locale/TranslatableConfiguration.cpp @@ -53,7 +53,6 @@ TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) } else if ( subkey.startsWith( key ) ) { - cDebug() << "Checking" << subkey; QRegularExpressionMatch match; if ( subkey.indexOf( QRegularExpression("\\[([a-zA-Z_@]*)\\]"), 0, &match ) > 0 ) { @@ -64,5 +63,17 @@ TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) } } +QString TranslatedString::get() const +{ + return get( QLocale() ); +} + +QString TranslatedString::get(const QLocale& locale) const +{ + cDebug() << "Getting locale" << locale.name(); + return m_strings[QString()]; +} + + } // namespace Locale } // namespace CalamaresUtils diff --git a/src/libcalamares/locale/TranslatableConfiguration.h b/src/libcalamares/locale/TranslatableConfiguration.h index 01bdf8ed6..b5a18ee73 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.h +++ b/src/libcalamares/locale/TranslatableConfiguration.h @@ -47,6 +47,12 @@ namespace Locale int count() const { return m_strings.count(); } + /// @brief Gets the string in the current locale + QString get() const; + + /// @brief Gets the string from the given locale + QString get(const QLocale&) const; + private: // Maps locale name to human-readable string, "" is English QMap< QString, QString > m_strings; From a9292d0c75316d2956ea70df0ce0aae7222c583f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 5 Aug 2019 23:54:53 +0200 Subject: [PATCH 09/15] [libcalamares] Implement getting the string --- src/libcalamares/locale/Tests.cpp | 58 ++++++++++--------- .../locale/TranslatableConfiguration.cpp | 53 ++++++++++++----- .../locale/TranslatableConfiguration.h | 54 ++++++++--------- 3 files changed, 98 insertions(+), 67 deletions(-) diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index 1cfd733a0..6f8310233 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -21,8 +21,8 @@ #include "locale/LabelModel.h" #include "locale/TranslatableConfiguration.h" -#include "utils/Logger.h" #include "CalamaresVersion.h" +#include "utils/Logger.h" #include @@ -88,60 +88,64 @@ LocaleTests::testEsperanto() static const QStringList& someLanguages() { - static QStringList languages{ "nl", "de", "da", "nb", "sr@latin", "ar", "ru" }; + static QStringList languages { "nl", "de", "da", "nb", "sr@latin", "ar", "ru" }; return languages; - } +} - - void LocaleTests::testTranslatableLanguages() + +void +LocaleTests::testTranslatableLanguages() { QStringList availableLanguages = QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';' ); cDebug() << "Translation languages:" << availableLanguages; - for ( const auto& language: someLanguages() ) + for ( const auto& language : someLanguages() ) { // Could be QVERIFY, but then we don't see what language code fails QCOMPARE( availableLanguages.contains( language ) ? language : QString(), language ); } } -void LocaleTests::testTranslatableConfig1() +void +LocaleTests::testTranslatableConfig1() { CalamaresUtils::Locale::TranslatedString ts1( "Hello" ); QCOMPARE( ts1.count(), 1 ); - + QCOMPARE( ts1.get(), "Hello" ); - QCOMPARE( ts1.get( QLocale("nl")), "Hello" ); - + QCOMPARE( ts1.get( QLocale( "nl" ) ), "Hello" ); + QVariantMap map; map.insert( "description", "description (no language)" ); - CalamaresUtils::Locale::TranslatedString ts2(map, "description"); + CalamaresUtils::Locale::TranslatedString ts2( map, "description" ); QCOMPARE( ts2.count(), 1 ); - - QCOMPARE( ts2.get(), "description (no language)"); - QCOMPARE( ts2.get( QLocale( "nl" ) ), "description (no language)"); + + QCOMPARE( ts2.get(), "description (no language)" ); + QCOMPARE( ts2.get( QLocale( "nl" ) ), "description (no language)" ); } -void LocaleTests::testTranslatableConfig2() +void +LocaleTests::testTranslatableConfig2() { QVariantMap map; - - for ( const auto& language: someLanguages() ) + + for ( const auto& language : someLanguages() ) { - map.insert( QString("description[%1]").arg(language), QString("description (language %1)").arg(language) ); + map.insert( QString( "description[%1]" ).arg( language ), + QString( "description (language %1)" ).arg( language ) ); if ( language != "nl" ) { - map.insert( QString("name[%1]").arg(language), QString("name (language %1)").arg(language) ); + map.insert( QString( "name[%1]" ).arg( language ), QString( "name (language %1)" ).arg( language ) ); } } - - CalamaresUtils::Locale::TranslatedString ts1(map, "description"); - // The +1 is because "" is always also inserted - QCOMPARE( ts1.count(), someLanguages().count()+1 ); - QCOMPARE( ts1.get(), "description"); // it wasn't set - QCOMPARE( ts1.get( QLocale( "nl" ) ), "description (language nl)"); - - CalamaresUtils::Locale::TranslatedString ts2(map, "name"); + CalamaresUtils::Locale::TranslatedString ts1( map, "description" ); + // The +1 is because "" is always also inserted + QCOMPARE( ts1.count(), someLanguages().count() + 1 ); + + QCOMPARE( ts1.get(), "description" ); // it wasn't set + QCOMPARE( ts1.get( QLocale( "nl" ) ), "description (language nl)" ); + + CalamaresUtils::Locale::TranslatedString ts2( map, "name" ); // We skipped dutch this time QCOMPARE( ts2.count(), someLanguages().count() ); } diff --git a/src/libcalamares/locale/TranslatableConfiguration.cpp b/src/libcalamares/locale/TranslatableConfiguration.cpp index d7066a57c..0b4a6ff71 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.cpp +++ b/src/libcalamares/locale/TranslatableConfiguration.cpp @@ -30,11 +30,11 @@ namespace CalamaresUtils { namespace Locale { -TranslatedString::TranslatedString(const QString& string) +TranslatedString::TranslatedString( const QString& string ) { - m_strings[QString()]=string; + m_strings[ QString() ] = string; } -TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) +TranslatedString::TranslatedString( const QVariantMap& map, const QString& key ) { // Get the un-decorated value for the key QString value = CalamaresUtils::getString( map, key ); @@ -42,11 +42,11 @@ TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) { value = key; } - m_strings[QString()] = value; - + m_strings[ QString() ] = value; + for ( auto it = map.constKeyValueBegin(); it != map.constKeyValueEnd(); ++it ) { - QString subkey = (*it).first; + QString subkey = ( *it ).first; if ( subkey == key ) { // Already obtained, above @@ -54,24 +54,51 @@ TranslatedString::TranslatedString(const QVariantMap& map, const QString& key) else if ( subkey.startsWith( key ) ) { QRegularExpressionMatch match; - if ( subkey.indexOf( QRegularExpression("\\[([a-zA-Z_@]*)\\]"), 0, &match ) > 0 ) + if ( subkey.indexOf( QRegularExpression( "\\[([a-zA-Z_@]*)\\]" ), 0, &match ) > 0 ) { - QString language = match.captured(1); - m_strings[language] = (*it).second.toString(); + QString language = match.captured( 1 ); + m_strings[ language ] = ( *it ).second.toString(); } } } } -QString TranslatedString::get() const +QString +TranslatedString::get() const { return get( QLocale() ); } -QString TranslatedString::get(const QLocale& locale) const +QString +TranslatedString::get( const QLocale& locale ) const { - cDebug() << "Getting locale" << locale.name(); - return m_strings[QString()]; + QString localeName = locale.name(); + cDebug() << "Getting locale" << localeName; + if ( m_strings.contains( localeName ) ) + { + return m_strings[ localeName ]; + } + int index = localeName.indexOf( '@' ); + if ( index > 0 ) + { + localeName.truncate( index ); + if ( m_strings.contains( localeName ) ) + { + return m_strings[ localeName ]; + } + } + + index = localeName.indexOf( '_' ); + if ( index > 0 ) + { + localeName.truncate( index ); + if ( m_strings.contains( localeName ) ) + { + return m_strings[ localeName ]; + } + } + + return m_strings[ QString() ]; } diff --git a/src/libcalamares/locale/TranslatableConfiguration.h b/src/libcalamares/locale/TranslatableConfiguration.h index b5a18ee73..0735a2274 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.h +++ b/src/libcalamares/locale/TranslatableConfiguration.h @@ -29,34 +29,34 @@ namespace CalamaresUtils { namespace Locale { - /** @brief A human-readable string from a configuration file - * - * The configuration files can contain human-readable strings, - * but those need their own translations and are not supported - * by QObject::tr or anything else. +/** @brief A human-readable string from a configuration file + * + * The configuration files can contain human-readable strings, + * but those need their own translations and are not supported + * by QObject::tr or anything else. + */ +class DLLEXPORT TranslatedString +{ +public: + /** @brief Get all the translations connected to @p key */ - class DLLEXPORT TranslatedString - { - public: - /** @brief Get all the translations connected to @p key - */ - TranslatedString( const QVariantMap& map, const QString& key ); - /** @brief Not-actually-translated string. - */ - TranslatedString( const QString& string ); - - int count() const { return m_strings.count(); } - - /// @brief Gets the string in the current locale - QString get() const; - - /// @brief Gets the string from the given locale - QString get(const QLocale&) const; - - private: - // Maps locale name to human-readable string, "" is English - QMap< QString, QString > m_strings; - }; + TranslatedString( const QVariantMap& map, const QString& key ); + /** @brief Not-actually-translated string. + */ + TranslatedString( const QString& string ); + + int count() const { return m_strings.count(); } + + /// @brief Gets the string in the current locale + QString get() const; + + /// @brief Gets the string from the given locale + QString get( const QLocale& ) const; + +private: + // Maps locale name to human-readable string, "" is English + QMap< QString, QString > m_strings; +}; } // namespace Locale } // namespace CalamaresUtils From 764c775f08e77a3eb66209edc2a6bb1e54dafa77 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 6 Aug 2019 00:05:24 +0200 Subject: [PATCH 10/15] [libcalamares] Tighten tests, add special case - The tests should be run in C locale, otherwise the plain get() function uses the current locale, which will fail (e.g. running LANG=nl ./libcalamareslocaletest returns the Dutch strings for plain get, which isn't what we expect). - sr@latin is still special. --- src/libcalamares/locale/Tests.cpp | 16 ++++++++++++++++ .../locale/TranslatableConfiguration.cpp | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index 6f8310233..241d66bbd 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -108,6 +108,7 @@ LocaleTests::testTranslatableLanguages() void LocaleTests::testTranslatableConfig1() { + QCOMPARE( QLocale().name(), "C" ); // Otherwise plain get() is dubious CalamaresUtils::Locale::TranslatedString ts1( "Hello" ); QCOMPARE( ts1.count(), 1 ); @@ -126,6 +127,7 @@ LocaleTests::testTranslatableConfig1() void LocaleTests::testTranslatableConfig2() { + QCOMPARE( QLocale().name(), "C" ); // Otherwise plain get() is dubious QVariantMap map; for ( const auto& language : someLanguages() ) @@ -144,6 +146,20 @@ LocaleTests::testTranslatableConfig2() QCOMPARE( ts1.get(), "description" ); // it wasn't set QCOMPARE( ts1.get( QLocale( "nl" ) ), "description (language nl)" ); + for ( const auto& language : someLanguages() ) + { + // Skip Serbian (latin) because QLocale() constructed with it + // doesn't retain the @latin part. + if ( language == "sr@latin" ) + { + continue; + } + // Could be QVERIFY, but then we don't see what language code fails + QCOMPARE( ts1.get( language ) == QString( "description (language %1)" ).arg( language ) ? language : QString(), + language ); + } + QCOMPARE( ts1.get( QLocale( QLocale::Language::Serbian, QLocale::Script::LatinScript, QLocale::Country::Serbia ) ), + "description (language sr@latin)" ); CalamaresUtils::Locale::TranslatedString ts2( map, "name" ); // We skipped dutch this time diff --git a/src/libcalamares/locale/TranslatableConfiguration.cpp b/src/libcalamares/locale/TranslatableConfiguration.cpp index 0b4a6ff71..82923a5fa 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.cpp +++ b/src/libcalamares/locale/TranslatableConfiguration.cpp @@ -73,6 +73,12 @@ QString TranslatedString::get( const QLocale& locale ) const { QString localeName = locale.name(); + // Special case, sr@latin doesn't have the @latin reflected in the name + if ( locale.language() == QLocale::Language::Serbian && locale.script() == QLocale::Script::LatinScript ) + { + localeName = QStringLiteral( "sr@latin" ); + } + cDebug() << "Getting locale" << localeName; if ( m_strings.contains( localeName ) ) { From fd75b3378418efd3106d8b6b874b3fef96447454 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 6 Aug 2019 00:17:30 +0200 Subject: [PATCH 11/15] [libcalamares] Add default constructor to TranslatedString --- src/libcalamares/locale/TranslatableConfiguration.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcalamares/locale/TranslatableConfiguration.h b/src/libcalamares/locale/TranslatableConfiguration.h index 0735a2274..b2f598069 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.h +++ b/src/libcalamares/locale/TranslatableConfiguration.h @@ -44,6 +44,9 @@ public: /** @brief Not-actually-translated string. */ TranslatedString( const QString& string ); + /// @brief Empty string + TranslatedString() + : TranslatedString( QString() ) {} int count() const { return m_strings.count(); } From 56db9e93412c897bc86be85b2c99ab5379617360 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 6 Aug 2019 00:17:50 +0200 Subject: [PATCH 12/15] [packagechooser] Use translated strings --- src/modules/packagechooser/PackageChooserPage.cpp | 4 ++-- src/modules/packagechooser/PackageModel.cpp | 4 ++-- src/modules/packagechooser/PackageModel.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/packagechooser/PackageChooserPage.cpp b/src/modules/packagechooser/PackageChooserPage.cpp index 60becf64f..0587af190 100644 --- a/src/modules/packagechooser/PackageChooserPage.cpp +++ b/src/modules/packagechooser/PackageChooserPage.cpp @@ -54,9 +54,9 @@ PackageChooserPage::currentChanged( const QModelIndex& index ) { if ( !index.isValid() || !ui->products->selectionModel()->hasSelection() ) { - ui->productName->setText( m_introduction.name ); + ui->productName->setText( m_introduction.name.get() ); ui->productScreenshot->setPixmap( m_introduction.screenshot ); - ui->productDescription->setText( m_introduction.description ); + ui->productDescription->setText( m_introduction.description.get() ); } else { diff --git a/src/modules/packagechooser/PackageModel.cpp b/src/modules/packagechooser/PackageModel.cpp index aa8dd39fc..f133f4fbd 100644 --- a/src/modules/packagechooser/PackageModel.cpp +++ b/src/modules/packagechooser/PackageModel.cpp @@ -118,11 +118,11 @@ PackageListModel::data( const QModelIndex& index, int role ) const if ( role == Qt::DisplayRole /* Also PackageNameRole */ ) { - return m_packages[ row ].name; + return m_packages[ row ].name.get(); } else if ( role == DescriptionRole ) { - return m_packages[ row ].description; + return m_packages[ row ].description.get(); } else if ( role == ScreenshotRole ) { diff --git a/src/modules/packagechooser/PackageModel.h b/src/modules/packagechooser/PackageModel.h index 7f8fff8ec..68e19a25d 100644 --- a/src/modules/packagechooser/PackageModel.h +++ b/src/modules/packagechooser/PackageModel.h @@ -19,6 +19,7 @@ #ifndef PACKAGEMODEL_H #define PACKAGEMODEL_H +#include "locale/TranslatableConfiguration.h" #include "utils/NamedEnum.h" #include @@ -41,9 +42,8 @@ struct PackageItem QString id; // TODO: may need more than one QString package; - // TODO: name and description are localized - QString name; - QString description; + CalamaresUtils::Locale::TranslatedString name; + CalamaresUtils::Locale::TranslatedString description; // TODO: may be more than one QPixmap screenshot; From fee2297e67639cdcd0a10f4889fec87cc747237c Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 6 Aug 2019 00:24:53 +0200 Subject: [PATCH 13/15] [packagechooser] Fix fallthrough situation - Add a FALLTHRU macro to annotate fallthrough situations in both Clang and GCC, - Annotate intentional fallthroughs. - Add missing break which meant that the selection mode was always multiple-selection. --- CMakeLists.txt | 4 ++-- src/modules/packagechooser/PackageChooserPage.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e38c1db9b..e28d28f38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,7 @@ if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) ) string( APPEND CMAKE_CXX_FLAGS " ${CLANG_WARNINGS}" ) endforeach() - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOTREACHED='//'" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOTREACHED='//' -DFALLTHRU='[[clang::fallthrough]]'") # Third-party code where we don't care so much about compiler warnings # (because it's uncomfortable to patch) get different flags; use @@ -225,7 +225,7 @@ else() set( SUPPRESS_3RDPARTY_WARNINGS "" ) set( SUPPRESS_BOOST_WARNINGS "" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOTREACHED='__builtin_unreachable();'" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOTREACHED='__builtin_unreachable();' -DFALLTHRU='/* */'" ) endif() # Use mark_thirdparty_code() to reduce warnings from the compiler diff --git a/src/modules/packagechooser/PackageChooserPage.cpp b/src/modules/packagechooser/PackageChooserPage.cpp index 0587af190..6f565c914 100644 --- a/src/modules/packagechooser/PackageChooserPage.cpp +++ b/src/modules/packagechooser/PackageChooserPage.cpp @@ -41,9 +41,12 @@ PackageChooserPage::PackageChooserPage( PackageChooserMode mode, QWidget* parent switch ( mode ) { case PackageChooserMode::Optional: + FALLTHRU; case PackageChooserMode::Required: ui->products->setSelectionMode( QAbstractItemView::SingleSelection ); + break; case PackageChooserMode::OptionalMultiple: + FALLTHRU; case PackageChooserMode::RequiredMultiple: ui->products->setSelectionMode( QAbstractItemView::ExtendedSelection ); } From 6a8e10837d044dc892804a5120ae4b462556f625 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 6 Aug 2019 00:26:04 +0200 Subject: [PATCH 14/15] [libcalamares] Drop unneeded debugging --- src/libcalamares/locale/TranslatableConfiguration.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcalamares/locale/TranslatableConfiguration.cpp b/src/libcalamares/locale/TranslatableConfiguration.cpp index 82923a5fa..b3b5259c9 100644 --- a/src/libcalamares/locale/TranslatableConfiguration.cpp +++ b/src/libcalamares/locale/TranslatableConfiguration.cpp @@ -79,7 +79,6 @@ TranslatedString::get( const QLocale& locale ) const localeName = QStringLiteral( "sr@latin" ); } - cDebug() << "Getting locale" << localeName; if ( m_strings.contains( localeName ) ) { return m_strings[ localeName ]; From 8d3546f0b3a4c1b8ceeb4467f8e80a2b9f8ea503 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 6 Aug 2019 00:31:05 +0200 Subject: [PATCH 15/15] [packagechooser] Expand the example config with translated entries --- src/modules/packagechooser/packagechooser.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/packagechooser/packagechooser.conf b/src/modules/packagechooser/packagechooser.conf index 391e1f325..7d60b50a4 100644 --- a/src/modules/packagechooser/packagechooser.conf +++ b/src/modules/packagechooser/packagechooser.conf @@ -44,12 +44,14 @@ items: - id: "" package: "" name: "No Desktop" + name[nl]: "Geen desktop" description: "Please pick a desktop environment from the list. If you don't want to install a desktop, that's fine, your system will start up in text-only mode and you can install a desktop environment later." + description[nl]: "Kies eventueel een desktop-omgeving uit deze lijst. Als u geen desktop-omgeving wenst te gebruiken, kies er dan geen. In dat geval start het systeem straks op in tekst-modus en kunt u later alsnog een desktop-omgeving installeren." screenshot: ":/images/no-selection.png" - id: kde package: kde name: Plasma Desktop - description: "KDE Plasma Desktop, DERP" + description: "KDE Plasma Desktop, simple by default, a clean work area for real-world usage which intends to stay out of your way. Plasma is powerful when needed, enabling the user to create the workflow that makes them more effective to complete their tasks." screenshot: ":/images/kde.png" - id: gnome package: gnome