Merge branch 'calamares' into work-3.3

This commit is contained in:
Adriaan de Groot 2022-05-05 23:35:53 +02:00
commit 21aa608ce2

View File

@ -13,45 +13,88 @@
#include <memory>
struct TranslationSpecialCase
{
const char* id; // The Calamares ID for the translation
const char** regions;
QLocale::Language language;
QLocale::Script script;
QLocale::Country country;
const char* name; // Native name, if different from Qt
constexpr bool customLocale() const { return language != QLocale::Language::AnyLanguage; }
};
/** @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.
* 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.
*
* Returns a pair of nullptrs for non-special cases.
* 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 std::pair< QLocale*, QString* >
specialCase( const CalamaresUtils::Locale::Translation::Id& locale )
{
const QString localeName = locale.name;
if ( localeName == "sr@latin" )
{
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 };
}
static const char* serbian_latin_regions[] = { "latin", "latn", nullptr };
static const char* catalan_regions[] = { "valencia", nullptr };
static constexpr const TranslationSpecialCase special_cases[] = {
{ "sr@latin",
serbian_latin_regions,
QLocale::Language::Serbian,
QLocale::Script::LatinScript,
QLocale::Country::Serbia,
nullptr },
// Valencian is a regional variant of Catalan
{ "ca@valencia",
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",
nullptr,
QLocale::Language::AnyLanguage,
QLocale::Script::AnyScript,
QLocale::Country::AnyCountry,
"简体中文" },
// Traditional Chinese, but drop (Taiwan) from the name
{ "zh_TW",
nullptr,
QLocale::Language::AnyLanguage,
QLocale::Script::AnyScript,
QLocale::Country::AnyCountry,
"繁體中文" },
{ "oc",
nullptr,
QLocale::Language::AnyLanguage,
QLocale::Script::AnyScript,
QLocale::Country::AnyCountry,
"Lenga d'òc" },
};
return { nullptr, nullptr };
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
@ -59,25 +102,24 @@ specialCaseSystemLanguage()
{
const QByteArray lang_p = qgetenv( "LANG" );
if ( lang_p.isEmpty() )
return {};
QString lang = QString::fromLatin1( lang_p );
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 ) )
{
return serbian_latin;
// This will figure out the system language some other way
return {};
}
const QString valencian = QStringLiteral( "ca@valencia" );
if ( lang == valencian )
auto lang_parts = lang_p.split( '@' );
if ( lang_parts.size() != 2 )
{
return valencian;
return {};
}
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
@ -95,11 +137,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() )
@ -125,8 +170,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