From a8857e51f47bb77ea920644efdd65f0e8c0bbbf3 Mon Sep 17 00:00:00 2001 From: Lt-Henry Date: Thu, 5 May 2022 11:12:29 +0200 Subject: [PATCH 1/4] Improving special-case language detection --- src/libcalamares/locale/Translation.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/libcalamares/locale/Translation.cpp b/src/libcalamares/locale/Translation.cpp index f0d74b0bf..08e47059f 100644 --- a/src/libcalamares/locale/Translation.cpp +++ b/src/libcalamares/locale/Translation.cpp @@ -64,17 +64,25 @@ specialCaseSystemLanguage() if ( lang.isEmpty() ) return {}; - const QString serbian_latin = QStringLiteral( "sr@latin" ); - const QString serbian_latin_variant = QStringLiteral( "sr@latn" ); - if ( ( lang == serbian_latin ) || ( lang == serbian_latin_variant ) ) + QStringList lang_parts = lang.split(QLatin1Char('@')); + if (lang_parts.size()!=2) + return {}; + + QString region = lang_parts[1]; + + QLocale locale(lang); + + const QString serbian_latin = QStringLiteral( "latin" ); + const QString serbian_latin_variant = QStringLiteral( "latn" ); + if ( locale.language() == QLocale::Serbian && ( region == serbian_latin || region == serbian_latin_variant ) ) { - return serbian_latin; + return QStringLiteral( "sr@latin" ); } - const QString valencian = QStringLiteral( "ca@valencia" ); - if ( lang == valencian ) + const QString valencian = QStringLiteral( "valencia" ); + if ( locale.language() == QLocale::Catalan && region == valencian ) { - return valencian; + return QStringLiteral( "ca@valencia" ); } return {}; From 2de7736291b39a2c16b074cde71863f70017b207 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 5 May 2022 14:42:12 +0200 Subject: [PATCH 2/4] [libcalamares] Replace locale special-cases by a table Replace the function with a table-driven approach, since that is somewhat easier to extend to more languages. --- src/libcalamares/locale/Translation.cpp | 110 ++++++++++++++---------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/src/libcalamares/locale/Translation.cpp b/src/libcalamares/locale/Translation.cpp index 08e47059f..798be1184 100644 --- a/src/libcalamares/locale/Translation.cpp +++ b/src/libcalamares/locale/Translation.cpp @@ -13,46 +13,59 @@ #include -/** @brief Handle special cases of Calamares language names - * - * If a given @p localeName (e.g. en_US, or sr@latin) has special handling, - * returns a pair of pointers: - * - a pointer to a QLocale; this is the locale to use, or may be @c nullptr - * to indicate that the Qt locale derived from @p localeName is accepatable. - * - a pointer to a QString; this is the native language name to use, or may - * be @c nullptr to indicate that the Qt value is acceptable. - * - * Returns a pair of nullptrs for non-special cases. - */ -static std::pair< QLocale*, QString* > -specialCase( const CalamaresUtils::Locale::Translation::Id& locale ) +struct TranslationSpecialCase { - const QString localeName = locale.name; - if ( localeName == "sr@latin" ) + const char* id; // The Calamares ID for the translation + + QLocale::Language language; + QLocale::Script script; + QLocale::Country country; + + const char* name; // Native name, if different from Qt + + constexpr TranslationSpecialCase( const char* i, + QLocale::Language l, + QLocale::Script s, + QLocale::Country c, + const char* n ) + : id( i ) + , language( l ) + , script( s ) + , country( c ) + , name( n ) { - static QLocale loc( QLocale::Language::Serbian, QLocale::Script::LatinScript, QLocale::Country::Serbia ); - return { &loc, nullptr }; - } - if ( localeName == "ca@valencia" ) - { - static QString name = QStringLiteral( "Català (València)" ); - return { nullptr, &name }; - } - if ( localeName == "zh_CN" ) - { - // Simplified Chinese, but drop the (China) from the name - static QString name = QStringLiteral( "简体中文" ); - return { nullptr, &name }; - } - if ( localeName == "zh_TW" ) - { - // Traditional Chinese, but drop (Taiwan) from the name - static QString name = QStringLiteral( "繁體中文" ); - return { nullptr, &name }; } - return { nullptr, nullptr }; -} + constexpr bool customLocale() const { return language != QLocale::Language::AnyLanguage; } +}; + +/** @brief Handle special cases of Calamares language names + * + * If a given @p id (e.g. en_US, or sr@latin) has special handling, + * put an entry in this table. The QLocale constants are used when a + * particular @p id needs specific configuration, **if** @p language + * is not @c AnyLanguage. The @p name is used as a human-readable + * native name if the Qt name is not suitable. + * + * Examples: + * - `sr@latin` needs specific Qt Locale settnigs, but the name is OK + * - Chinese needs a specific name, but the Locale is OK + */ +static constexpr const TranslationSpecialCase special_cases[] = { + { "sr@latin", QLocale::Language::Serbian, QLocale::Script::LatinScript, QLocale::Country::Serbia, nullptr }, + // Valencian is a regional variant of Catalan + { "ca@valencia", + QLocale::Language::AnyLanguage, + QLocale::Script::AnyScript, + QLocale::Country::AnyCountry, + "Català (València)" }, + // Simplified Chinese, but drop the (China) from the name + { "zh_CN", QLocale::Language::AnyLanguage, QLocale::Script::AnyScript, QLocale::Country::AnyCountry, "简体中文" }, + // Traditional Chinese, but drop (Taiwan) from the name + { "zh_TW", QLocale::Language::AnyLanguage, QLocale::Script::AnyScript, QLocale::Country::AnyCountry, "繁體中文" }, +}; + +static_assert( std::size( special_cases ) == 4 ); static QString specialCaseSystemLanguage() @@ -64,13 +77,13 @@ specialCaseSystemLanguage() if ( lang.isEmpty() ) return {}; - QStringList lang_parts = lang.split(QLatin1Char('@')); - if (lang_parts.size()!=2) + QStringList lang_parts = lang.split( QLatin1Char( '@' ) ); + if ( lang_parts.size() != 2 ) return {}; - QString region = lang_parts[1]; + QString region = lang_parts[ 1 ]; - QLocale locale(lang); + QLocale locale( lang ); const QString serbian_latin = QStringLiteral( "latin" ); const QString serbian_latin_variant = QStringLiteral( "latn" ); @@ -103,11 +116,14 @@ Translation::Translation( const Id& localeId, LabelFormat format, QObject* paren , m_locale( getLocale( localeId ) ) , m_localeId( localeId.name.isEmpty() ? m_locale.name() : localeId.name ) { - auto [ _, name ] = specialCase( localeId ); + auto it = std::find_if( std::cbegin( special_cases ), + std::cend( special_cases ), + [ &localeId ]( const TranslationSpecialCase& s ) { return localeId.name == s.id; } ); + const char* name = ( it != std::cend( special_cases ) ) ? it->name : nullptr; QString longFormat = QObject::tr( "%1 (%2)" ); - QString languageName = name ? *name : m_locale.nativeLanguageName(); + QString languageName = name ? QString::fromUtf8( name ) : m_locale.nativeLanguageName(); QString englishName = m_locale.languageToString( m_locale.language() ); if ( languageName.isEmpty() ) @@ -133,8 +149,14 @@ Translation::getLocale( const Id& localeId ) return QLocale(); } - auto [ locale, _ ] = specialCase( localeId ); - return locale ? *locale : QLocale( localeName ); + auto it = std::find_if( std::cbegin( special_cases ), + std::cend( special_cases ), + [ &localeId ]( const TranslationSpecialCase& s ) { return localeId.name == s.id; } ); + if ( it != std::cend( special_cases ) && it->customLocale() ) + { + return QLocale( it->language, it->script, it->country ); + } + return QLocale( localeName ); } } // namespace Locale From 4be25e2f70256c169f64cf44f6a131ad95ef0697 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 5 May 2022 15:20:29 +0200 Subject: [PATCH 3/4] [libcalamares] Special-case the regions through the lookup-table as well --- src/libcalamares/locale/Translation.cpp | 93 +++++++++++++++---------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/src/libcalamares/locale/Translation.cpp b/src/libcalamares/locale/Translation.cpp index 798be1184..584de9648 100644 --- a/src/libcalamares/locale/Translation.cpp +++ b/src/libcalamares/locale/Translation.cpp @@ -16,6 +16,7 @@ struct TranslationSpecialCase { const char* id; // The Calamares ID for the translation + const char** regions; QLocale::Language language; QLocale::Script script; @@ -23,19 +24,6 @@ struct TranslationSpecialCase const char* name; // Native name, if different from Qt - constexpr TranslationSpecialCase( const char* i, - QLocale::Language l, - QLocale::Script s, - QLocale::Country c, - const char* n ) - : id( i ) - , language( l ) - , script( s ) - , country( c ) - , name( n ) - { - } - constexpr bool customLocale() const { return language != QLocale::Language::AnyLanguage; } }; @@ -47,58 +35,87 @@ struct TranslationSpecialCase * is not @c AnyLanguage. The @p name is used as a human-readable * native name if the Qt name is not suitable. * + * Another form of lookup maps a @p language + a region-identifier + * to a @p id, running around Qt's neglect of `@region` variants. + * * Examples: * - `sr@latin` needs specific Qt Locale settnigs, but the name is OK * - Chinese needs a specific name, but the Locale is OK */ +static const char* serbian_latin_regions[] = { "latin", "latn", nullptr }; +static const char* catalan_regions[] = { "valencia", nullptr }; static constexpr const TranslationSpecialCase special_cases[] = { - { "sr@latin", QLocale::Language::Serbian, QLocale::Script::LatinScript, QLocale::Country::Serbia, nullptr }, + { "sr@latin", + serbian_latin_regions, + QLocale::Language::Serbian, + QLocale::Script::LatinScript, + QLocale::Country::Serbia, + nullptr }, // Valencian is a regional variant of Catalan { "ca@valencia", - QLocale::Language::AnyLanguage, + catalan_regions, + QLocale::Language::Catalan, QLocale::Script::AnyScript, QLocale::Country::AnyCountry, "Català (València)" }, // Simplified Chinese, but drop the (China) from the name - { "zh_CN", QLocale::Language::AnyLanguage, QLocale::Script::AnyScript, QLocale::Country::AnyCountry, "简体中文" }, + { "zh_CN", + nullptr, + QLocale::Language::AnyLanguage, + QLocale::Script::AnyScript, + QLocale::Country::AnyCountry, + "简体中文" }, // Traditional Chinese, but drop (Taiwan) from the name - { "zh_TW", QLocale::Language::AnyLanguage, QLocale::Script::AnyScript, QLocale::Country::AnyCountry, "繁體中文" }, + { "zh_TW", + nullptr, + QLocale::Language::AnyLanguage, + QLocale::Script::AnyScript, + QLocale::Country::AnyCountry, + "繁體中文" }, }; static_assert( std::size( special_cases ) == 4 ); +static inline bool +lookup_region( const QByteArray& region, const char** regions_list ) +{ + if ( regions_list ) + { + while ( *regions_list ) + { + if ( region == *regions_list ) + { + return true; + } + regions_list++; + } + } + return false; +} + static QString specialCaseSystemLanguage() { const QByteArray lang_p = qgetenv( "LANG" ); if ( lang_p.isEmpty() ) + { + // This will figure out the system language some other way return {}; - QString lang = QString::fromLatin1( lang_p ); - if ( lang.isEmpty() ) - return {}; + } - QStringList lang_parts = lang.split( QLatin1Char( '@' ) ); + auto lang_parts = lang_p.split( '@' ); if ( lang_parts.size() != 2 ) + { return {}; - - QString region = lang_parts[ 1 ]; - - QLocale locale( lang ); - - const QString serbian_latin = QStringLiteral( "latin" ); - const QString serbian_latin_variant = QStringLiteral( "latn" ); - if ( locale.language() == QLocale::Serbian && ( region == serbian_latin || region == serbian_latin_variant ) ) - { - return QStringLiteral( "sr@latin" ); } - const QString valencian = QStringLiteral( "valencia" ); - if ( locale.language() == QLocale::Catalan && region == valencian ) - { - return QStringLiteral( "ca@valencia" ); - } - - return {}; + QLocale locale( QString::fromLatin1( lang_p ) ); + auto it + = std::find_if( std::cbegin( special_cases ), + std::cend( special_cases ), + [ language = locale.language(), region = lang_parts[ 1 ] ]( const TranslationSpecialCase& s ) + { return ( s.language == language ) && lookup_region( region, s.regions ); } ); + return ( it != std::cend( special_cases ) ) ? QString::fromLatin1( it->id ) : QString(); } namespace CalamaresUtils From 091eb9683b58ed7febb5d93472b209388d28c655 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 5 May 2022 15:23:54 +0200 Subject: [PATCH 4/4] [libcalamares] Give Occitan a native name --- src/libcalamares/locale/Translation.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/locale/Translation.cpp b/src/libcalamares/locale/Translation.cpp index 584de9648..213d2b9a7 100644 --- a/src/libcalamares/locale/Translation.cpp +++ b/src/libcalamares/locale/Translation.cpp @@ -72,10 +72,14 @@ static constexpr const TranslationSpecialCase special_cases[] = { QLocale::Script::AnyScript, QLocale::Country::AnyCountry, "繁體中文" }, + { "oc", + nullptr, + QLocale::Language::AnyLanguage, + QLocale::Script::AnyScript, + QLocale::Country::AnyCountry, + "Lenga d'òc" }, }; -static_assert( std::size( special_cases ) == 4 ); - static inline bool lookup_region( const QByteArray& region, const char** regions_list ) {