diff --git a/src/modules/users/CMakeLists.txt b/src/modules/users/CMakeLists.txt index 92a9e03e7..2772a6b39 100644 --- a/src/modules/users/CMakeLists.txt +++ b/src/modules/users/CMakeLists.txt @@ -21,6 +21,18 @@ if( LibPWQuality_FOUND ) add_definitions( -DCHECK_PWQUALITY -DHAVE_LIBPWQUALITY ) endif() +find_package( ICU COMPONENTS uc i18n ) +set_package_properties( + ICU PROPERTIES + PURPOSE "Transliteration support for full name to username conversion" +) + +if( ICU_FOUND ) + list( APPEND USER_EXTRA_LIB ICU::uc ICU::i18n ) + include_directories( ${ICU_INCLUDE_DIRS} ) + add_definitions( -DHAVE_ICU ) +endif() + include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) set( _users_src diff --git a/src/modules/users/Config.cpp b/src/modules/users/Config.cpp index 77f52b466..ba7341a9c 100644 --- a/src/modules/users/Config.cpp +++ b/src/modules/users/Config.cpp @@ -24,6 +24,18 @@ #include #include +#ifdef HAVE_ICU +#include +#include + +//Needed for ICU to apply some transliteration ruleset. +//Still needs to be adjusted to fit the needs of the most of users +static const char TRANSLITERATOR_ID[] = "Russian-Latin/BGN;" + "Greek-Latin/UNGEGN;" + "Any-Latin;" + "Latin-ASCII"; +#endif + static const QRegExp USERNAME_RX( "^[a-z_][a-z0-9_-]*[$]?$" ); static constexpr const int USERNAME_MAX_LENGTH = 31; @@ -91,7 +103,7 @@ Config::Config( QObject* parent ) connect( this, &Config::requireStrongPasswordsChanged, this, &Config::checkReady ); } -Config::~Config() {} +Config::~Config() { } void Config::setUserShell( const QString& shell ) @@ -314,6 +326,33 @@ guessProductName() } return dmiProduct; } +#ifdef HAVE_ICU +static QString +transliterate( const QString& input ) +{ + static auto ue = UErrorCode::U_ZERO_ERROR; + static auto transliterator = std::unique_ptr< icu::Transliterator >( + icu::Transliterator::createInstance( TRANSLITERATOR_ID, UTRANS_FORWARD, ue ) ); + + if ( ue != UErrorCode::U_ZERO_ERROR ) + { + cWarning() << "Can't create transliterator"; + + //it'll be checked later for non-ASCII characters + return input; + } + + icu::UnicodeString transliterable( input.utf16() ); + transliterator->transliterate( transliterable ); + return QString::fromUtf16( transliterable.getTerminatedBuffer() ); +} +#else +static QString +transliterate( const QString& input ) +{ + return input; +} +#endif static QString makeLoginNameSuggestion( const QStringList& parts ) @@ -372,8 +411,15 @@ Config::setFullName( const QString& name ) emit fullNameChanged( name ); // Build login and hostname, if needed - QRegExp rx( "[^a-zA-Z0-9 ]", Qt::CaseInsensitive ); - QString cleanName = CalamaresUtils::removeDiacritics( name ).toLower().replace( rx, " " ).simplified(); + static QRegExp rx( "[^a-zA-Z0-9 ]", Qt::CaseInsensitive ); + + QString cleanName = CalamaresUtils::removeDiacritics( transliterate( name ) ) + .replace( QRegExp( "[-']" ), "" ) + .replace( rx, " " ) + .toLower() + .simplified(); + + QStringList cleanParts = cleanName.split( ' ' ); if ( !m_customLoginName ) diff --git a/src/modules/usersq/CMakeLists.txt b/src/modules/usersq/CMakeLists.txt index 7e3fffb8d..583a3384b 100644 --- a/src/modules/usersq/CMakeLists.txt +++ b/src/modules/usersq/CMakeLists.txt @@ -28,6 +28,19 @@ if( LibPWQuality_FOUND ) add_definitions( -DCHECK_PWQUALITY -DHAVE_LIBPWQUALITY ) endif() +#needed for ${_users}/Config.cpp +find_package( ICU COMPONENTS uc i18n ) +set_package_properties( + ICU PROPERTIES + PURPOSE "Transliteration support for full name to username conversion" +) + +if( ICU_FOUND ) + list( APPEND USER_EXTRA_LIB ICU::uc ICU::i18n ) + include_directories( ${ICU_INCLUDE_DIRS} ) + add_definitions( -DHAVE_ICU ) +endif() + calamares_add_plugin( usersq TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO