diff --git a/.travis.yml b/.travis.yml index a9fcbb28b..9f52226bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,5 +19,5 @@ install: - docker build -t calamares . script: - - docker run -v $PWD:/src --tmpfs /build:rw,size=81920k -e SRCDIR=/src -e BUILDDIR=/build calamares "/src/ci/travis.sh" + - docker run -v $PWD:/src --tmpfs /build:rw,size=112M -e SRCDIR=/src -e BUILDDIR=/build calamares "/src/ci/travis.sh" diff --git a/CHANGES b/CHANGES index 84b7d545d..a9b179e6b 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,55 @@ contributors are listed. Note that Calamares does not have a historical changelog -- this log starts with version 3.2.0. The release notes on the website will have to do for older versions. +# 3.2.34 (unreleased) # + +This release contains contributions from (alphabetically by first name): + - Artem Grinev + +## Core ## + - No core changes yet + +## Modules ## + - In the *users* module, warnings about the strength of the password + are now correctly pluralized when possible. + - In the *users* module, if ICU is installed, the user's full name is + automatically transliterated to US-ASCII (for some locales; this will + need tweaking) so that the login name is acceptable. (Thanks Artem) + + +# 3.2.33 (2020-11-09) # + +This release contains contributions from (alphabetically by first name): + - Anke Boersma + - Andrius Štikonas + - Artem Grinev + - Gaël PORTAY + - Matti Hyttinen + - TTran Me + +## Core ## + - Calamares now sets the C++ standard for compilation to C++17; this + is for better compatibility and fewer warnings when building with + modern KDE Frameworks and KPMcore 4.2.0. + - Vietnamese translations have been added. Welcome! (Thanks TTran) + +## Modules ## + - The *initcpiocfg* module should support plymouth with encryption + now. (Thanks Matti) + - The *keyboard* and *keyboardq* modules now share backend code + and handle non-ASCII layouts better (for setting passwords + and usernames). (Thanks Artem) + - Various cleanups and documentation improvements in the *partition* + module, and configurable GPT name for swap. (Thanks Gaël) + - A long-standing bug related to GPT partition flags in the + *partition* module has been resolved. #1327 #1267 + - The *users* module now has a more detailed way to specify + user groups -- which may be system groups rather than user-GIDs. + A new option in each group can require that the group already + exists in the target system, allowing for better consistency checks + with the squashfs. #1523 + + # 3.2.32.1 (2020-10-17) # This is a release to address source-incompatible changes in KPMcore 4.2.0, diff --git a/CMakeLists.txt b/CMakeLists.txt index 64acdece3..fbd9d9432 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,10 +41,10 @@ # TODO:3.3: Require CMake 3.12 cmake_minimum_required( VERSION 3.3 FATAL_ERROR ) project( CALAMARES - VERSION 3.2.32.1 + VERSION 3.2.34 LANGUAGES C CXX ) -set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development +set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development ### OPTIONS # @@ -140,12 +140,13 @@ set( CALAMARES_DESCRIPTION_SUMMARY # NOTE: update these lines by running `txstats.py`, or for full automation # `txstats.py -e`. See also # -# Total 70 languages -set( _tx_complete ca cs_CZ he hr sq tr_TR uk ) -set( _tx_good as ast az az_AZ be da de es fa fi_FI fr hi hu it_IT - ja ko lt ml nl pt_BR pt_PT ru sk sv tg zh_CN zh_TW ) -set( _tx_ok ar bg bn el en_GB es_MX es_PR et eu fur gl id is mr nb - pl ro sl sr sr@latin th ) +# Total 71 languages +set( _tx_complete az az_AZ be ca cs_CZ da de fi_FI fur he hi hr ja + pt_BR sq sv tg uk vi zh_TW ) +set( _tx_good as ast es fa fr hu it_IT ko lt ml nl pt_PT ru sk + tr_TR zh_CN ) +set( _tx_ok ar bg bn el en_GB es_MX es_PR et eu gl id is mr nb pl + ro sl sr sr@latin th ) set( _tx_incomplete ca@valencia eo fr_CH gu ie kk kn lo lv mk ne_NP te ur uz ) @@ -190,23 +191,30 @@ include( CMakeColors ) ### C++ SETUP # -set( CMAKE_CXX_STANDARD 14 ) +set( CMAKE_CXX_STANDARD 17 ) set( CMAKE_CXX_STANDARD_REQUIRED ON ) +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror=return-type" ) +set( CMAKE_CXX_FLAGS_DEBUG "-g ${CMAKE_CXX_FLAGS_DEBUG}" ) +set( CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG" ) +set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" ) +set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g" ) + set( CMAKE_C_STANDARD 99 ) set( CMAKE_C_STANDARD_REQUIRED ON ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall" ) +set( CMAKE_C_FLAGS_DEBUG "-g" ) +set( CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" ) +set( CMAKE_C_FLAGS_RELEASE "-O4 -DNDEBUG" ) +set( CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" ) + +set( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined -Wl,--fatal-warnings" ) + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) message( STATUS "Found Clang ${CMAKE_CXX_COMPILER_VERSION}, setting up Clang-specific compiler flags." ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall" ) - set( CMAKE_C_FLAGS_DEBUG "-g" ) - set( CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" ) - set( CMAKE_C_FLAGS_RELEASE "-O4 -DNDEBUG" ) - set( CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" ) # Clang warnings: doing *everything* is counter-productive, since it warns # about things which we can't fix (e.g. C++98 incompatibilities, but - # Calamares is C++14). + # Calamares is C++17). foreach( CLANG_WARNINGS -Weverything -Wno-c++98-compat @@ -218,40 +226,26 @@ if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) -Wno-missing-prototypes -Wno-documentation-unknown-command -Wno-unknown-warning-option - -Werror=return-type ) string( APPEND CMAKE_CXX_FLAGS " ${CLANG_WARNINGS}" ) endforeach() - 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 # mark_thirdparty_code( [...] ) # to switch off warnings for those sources. set( SUPPRESS_3RDPARTY_WARNINGS "-Wno-everything" ) - set( SUPPRESS_BOOST_WARNINGS " -Wno-zero-as-null-pointer-constant -Wno-disabled-macro-expansion" ) - - set( CMAKE_CXX_FLAGS_DEBUG "-g ${CMAKE_CXX_FLAGS_DEBUG}" ) - set( CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG" ) - set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" ) - set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g" ) set( CMAKE_TOOLCHAIN_PREFIX "llvm-" ) - set( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined" ) - # The path prefix is only relevant for CMake 3.16 and later, fixes #1286 set( CMAKE_AUTOMOC_PATH_PREFIX OFF ) set( CALAMARES_AUTOMOC_OPTIONS "-butils/moc-warnings.h" ) set( CALAMARES_AUTOUIC_OPTIONS --include utils/moc-warnings.h ) else() - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--no-undefined" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--fatal-warnings -Wnon-virtual-dtor -Woverloaded-virtual -Werror=return-type" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Woverloaded-virtual" ) set( SUPPRESS_3RDPARTY_WARNINGS "" ) - set( SUPPRESS_BOOST_WARNINGS "" ) - - 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/CMakeModules/CalamaresAddTest.cmake b/CMakeModules/CalamaresAddTest.cmake index 56a45d7dc..228d7cbc0 100644 --- a/CMakeModules/CalamaresAddTest.cmake +++ b/CMakeModules/CalamaresAddTest.cmake @@ -42,6 +42,8 @@ function( calamares_add_test ) Qt5::Test ) calamares_automoc( ${TEST_NAME} ) + # We specifically pass in the source directory of the test-being- + # compiled, so that it can find test-files in that source dir. target_compile_definitions( ${TEST_NAME} PRIVATE -DBUILD_AS_TEST="${CMAKE_CURRENT_SOURCE_DIR}" ${TEST_DEFINITIONS} ) if( TEST_GUI ) target_link_libraries( ${TEST_NAME} calamaresui Qt5::Gui ) diff --git a/README.md b/README.md index 3049fbabc..d3db39089 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,10 @@ [![Coverity Scan Build Status](https://scan.coverity.com/projects/5389/badge.svg)](https://scan.coverity.com/projects/5389) [![GitHub license](https://img.shields.io/github/license/calamares/calamares.svg)](https://github.com/calamares/calamares/blob/calamares/LICENSE) -| [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Translate](https://www.transifex.com/projects/p/calamares/) | [Contribute](CONTRIBUTING.md) | [Freenode (IRC): #calamares](https://webchat.freenode.net/?channel=#calamares?nick=guest|) | [Wiki](https://github.com/calamares/calamares/wiki) | -|:-----------------------------------------:|:----------------------:|:-----------------------:|:--------------------------:|:--------------------------:| + +| [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Translate](https://www.transifex.com/projects/p/calamares/) | [Contribute](CONTRIBUTING.md) | [Freenode (IRC): #calamares](https://webchat.freenode.net/?channel=#calamares?nick=guest) | [Wiki](https://github.com/calamares/calamares/wiki) | +|:--:|:--:|:--:|:--:|:--:| + > Calamares is a distribution-independent system installer, with an advanced partitioning > feature for both manual and automated partitioning operations. Calamares is designed to @@ -37,8 +39,8 @@ Clone Calamares from GitHub. The default branch is called *calamares*. git clone https://github.com/calamares/calamares.git ``` -Calamares is a KDE-Frameworks and Qt-based, C++14, CMake-built application. -The dependencies are explainged in [CONTRIBUTING.md](CONTRIBUTING.md). +Calamares is a KDE-Frameworks and Qt-based, C++17, CMake-built application. +The dependencies are explained in [CONTRIBUTING.md](CONTRIBUTING.md). ## Contributing to Calamares diff --git a/calamares.desktop b/calamares.desktop index b6cafe612..834c4a518 100644 --- a/calamares.desktop +++ b/calamares.desktop @@ -201,6 +201,10 @@ Name[uk]=Встановити Систему Icon[uk]=calamares GenericName[uk]=Встановлювач системи Comment[uk]=Calamares - Встановлювач системи +Name[vi]=Cài đặt hệ thống +Icon[vi]=calamares +GenericName[vi]=Bộ cài đặt hệ thống +Comment[vi]=Calamares — Bộ cài đặt hệ thống Name[zh_CN]=安装系统 Icon[zh_CN]=calamares GenericName[zh_CN]=系统安装程序 diff --git a/ci/calamaresstyle b/ci/calamaresstyle index bd715eee1..42adc33cc 100755 --- a/ci/calamaresstyle +++ b/ci/calamaresstyle @@ -22,7 +22,7 @@ export LANG LC_ALL LC_NUMERIC AS=$( which astyle ) -CF_VERSIONS="clang-format-7 clang-format-8 clang-format70 clang-format80 clang-format-9.0.1 clang-format" +CF_VERSIONS="clang-format-7 clang-format-8 clang-format70 clang-format80 clang-format90 clang-format-9.0.1 clang-format" for _cf in $CF_VERSIONS do # Not an error if this particular clang-format isn't found diff --git a/ci/configvalidator.py b/ci/configvalidator.py index 5c0ee4559..cde3527f6 100644 --- a/ci/configvalidator.py +++ b/ci/configvalidator.py @@ -45,6 +45,7 @@ ERR_IMPORT, ERR_USAGE, ERR_FILE_NOT_FOUND, ERR_SYNTAX, ERR_INVALID = range(1,6) # try: from jsonschema import validate, SchemaError, ValidationError + from jsonschema import draft7_format_checker from yaml import safe_load, YAMLError except ImportError as e: print(e) diff --git a/ci/txpush.sh b/ci/txpush.sh index 363a234e8..ac806a2fa 100755 --- a/ci/txpush.sh +++ b/ci/txpush.sh @@ -92,9 +92,16 @@ done # those are done separately. _srcdirs="src/calamares src/libcalamares src/libcalamaresui src/modules src/qml" $LUPDATE -no-obsolete $_srcdirs -ts lang/calamares_en.ts -# Updating the TZ only needs to happen when the TZ themselves are updated, -# very-very-rarely. +# Non-Transifex special-cases +# +# - timezone names can be translated, but that's 700+ strings I don't want +# to inflict on translators normally +# - keyboard layouts can be translated, but that's 767 strings +# +# For both of these, the language / translation only needs to be updated +# when the source data is updated, which is very very rarely. # $LUPDATE -no-obsolete -extensions cxxtr src/libcalamares/locale -ts lang/tz_en.ts +# $LUPDATE -no-obsolete -extensions cxxtr src/modules/keyboard -ts lang/kb_en.ts if test -n "$XMLLINT" ; then TS_FILE="lang/calamares_en.ts" diff --git a/lang/calamares_az.ts b/lang/calamares_az.ts index e73b01885..cad678b40 100644 --- a/lang/calamares_az.ts +++ b/lang/calamares_az.ts @@ -619,17 +619,17 @@ Bu proqramdan çıxılacaq və bütün dəyişikliklər itiriləcəkdir. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Bu yaddaş qurğusunda artıq əməliyyat sistemi var, lakin, bölmə cədvəli <strong>%1</strong>, lazım olan <strong>%2</strong> ilə fərqlidir.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Bu yaddaş qurğusunda bölmələrdən biri <strong>quraşdırılmışdır</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Bu yaddaş qurğusu <strong>qeyri-aktiv RAİD</strong> qurğusunun bir hissəsidir. @@ -2869,7 +2869,7 @@ Output: Directory not found - + Qovluq tapılmadı diff --git a/lang/calamares_az_AZ.ts b/lang/calamares_az_AZ.ts index 51ef10496..161a04990 100644 --- a/lang/calamares_az_AZ.ts +++ b/lang/calamares_az_AZ.ts @@ -619,17 +619,17 @@ Bu proqramdan çıxılacaq və bütün dəyişikliklər itiriləcəkdir. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Bu yaddaş qurğusunda artıq əməliyyat sistemi var, lakin, bölmə cədvəli <strong>%1</strong>, lazım olan <strong>%2</strong> ilə fərqlidir.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Bu yaddaş qurğusunda bölmələrdən biri <strong>quraşdırılmışdır</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Bu yaddaş qurğusu <strong>qeyri-aktiv RAİD</strong> qurğusunun bir hissəsidir. @@ -2869,7 +2869,7 @@ Output: Directory not found - + Qovluq tapılmadı diff --git a/lang/calamares_be.ts b/lang/calamares_be.ts index 27c5422ae..41502ddfc 100644 --- a/lang/calamares_be.ts +++ b/lang/calamares_be.ts @@ -532,7 +532,7 @@ The installer will quit and all changes will be lost. <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. - + <strong>Уласнаручная разметка</strong><br/>Вы можаце самастойна ствараць раздзелы або змяняць іх памеры. @@ -621,17 +621,17 @@ The installer will quit and all changes will be lost. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + На гэтай прыладзе ўжо ўсталяваная аперацыйная сістэма, але табліца раздзелаў <strong>%1</strong> не такая, як патрэбна <strong>%2</strong>.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Адзін з раздзелаў гэтай назапашвальнай прылады<strong>прымантаваны</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Гэтая назапашвальная прылада ёсць часткай<strong>неактыўнага RAID</strong>. @@ -734,7 +734,7 @@ The installer will quit and all changes will be lost. Set timezone to %1/%2. - + Вызначыць часавы пояс %1/%2. @@ -794,22 +794,22 @@ The installer will quit and all changes will be lost. <h1>Welcome to the Calamares setup program for %1</h1> - + <h1>Вітаем у праграме ўсталёўкі Calamares для %1</h1> <h1>Welcome to %1 setup</h1> - + <h1>Вітаем у праграме ўсталёўкі %1</h1> <h1>Welcome to the Calamares installer for %1</h1> - + <h1>Вітаем у праграме ўсталёўкі Calamares для %1</h1> <h1>Welcome to the %1 installer</h1> - + <h1>Вітаем у праграме ўсталёўкі %1</h1> @@ -819,7 +819,7 @@ The installer will quit and all changes will be lost. '%1' is not allowed as username. - + '%1' немагчыма выкарыстаць як імя карыстальніка. @@ -844,7 +844,7 @@ The installer will quit and all changes will be lost. '%1' is not allowed as hostname. - + '%1' немагчыма выкарыстаць як назву хоста. @@ -1817,14 +1817,16 @@ The installer will quit and all changes will be lost. Timezone: %1 - + Часавы пояс: %1 Please select your preferred location on the map so the installer can suggest the locale and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming. - + Калі ласка, абярыце неабходнае месца на мапе, каб праграма прапанавала мову + і налады часавога пояса. Вы можаце дакладна наладзіць прапанаваныя параметры ніжэй. Месца на мапе можна абраць перацягваючы + яе пры дапамозе мышы. Для павелічэння і памяншэння выкарыстоўвайце кнопкі +/- і кола мышы. @@ -1944,7 +1946,7 @@ The installer will quit and all changes will be lost. <html><head/><body><p>Enter a batch-identifier here. This will be stored in the target system.</p></body></html> - <html><head/><body><p>Увядзіце сюды масавы ідэнтыфікатар. Ён захавецца ў мэтавай сістэме.</p></body></html> + <html><head/><body><p>Увядзіце сюды масавы ідэнтыфікатар. Ён захаваецца ў мэтавай сістэме.</p></body></html> @@ -1970,29 +1972,29 @@ The installer will quit and all changes will be lost. Select your preferred Region, or use the default one based on your current location. - + Абярыце пераважны рэгіён альбо выкарыстоўвайце прадвызначаны ў залежнасці ад вашага бягучага месцазнаходжання. Timezone: %1 - + Часавы пояс: %1 Select your preferred Zone within your Region. - + Абярыце часавы пояс для вашага рэгіёна. Zones - + Часавыя паясы You can fine-tune Language and Locale settings below. - + Ніжэй вы можаце наладзіць мову і мясцовасць. @@ -2644,12 +2646,12 @@ The installer will quit and all changes will be lost. An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a FAT32 filesystem with the <strong>%3</strong> flag enabled and mount point <strong>%2</strong>.<br/><br/>You can continue without setting up an EFI system partition but your system may fail to start. - + Для таго, каб пачаць %1, патрабуецца сістэмны раздзел EFI.<br/><br/> Каб наладзіць сістэмны раздзел EFI, вярніцеся назад, абярыце альбо стварыце файлавую сістэму FAT32 са сцягам <strong>%3</strong> і пунктам мантавання <strong>%2</strong>.<br/><br/>Вы можаце працягнуць і без наладкі сістэмнага раздзела EFI, але ваша сістэма можа не загрузіцца. An EFI system partition is necessary to start %1.<br/><br/>A partition was configured with mount point <strong>%2</strong> but its <strong>%3</strong> flag is not set.<br/>To set the flag, go back and edit the partition.<br/><br/>You can continue without setting the flag but your system may fail to start. - + Для таго, каб пачаць %1, патрабуецца сістэмны раздзел EFI.<br/><br/>Быў наладжаны раздзел з пунктам мантавання<strong>%2</strong> але яго сцяг <strong>%3</strong> не вызначаны.<br/>Каб вызначыць сцяг, вярніцеся назад і адрэдагуйце раздзел.<br/><br/> Вы можаце працягнуць без наладкі раздзела, але ваша сістэма можа не загрузіцца. @@ -2868,7 +2870,7 @@ Output: Directory not found - + Каталог не знойдзены @@ -2903,7 +2905,8 @@ Output: <p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/> Setup can continue, but some features might be disabled.</p> - + <p>Гэты камп’ютар адпавядае не ўсім патрэбам для ўсталёўкі %1.<br/> + Можна працягнуць усталёўку, але некаторыя магчымасці могуць быць недаступнымі.</p> @@ -3014,13 +3017,15 @@ Output: <p>This computer does not satisfy the minimum requirements for installing %1.<br/> Installation cannot continue.</p> - + <p>Гэты камп’ютар не адпавядае мінімальным патрэбам для ўсталёўкі %1.<p> + Немагчыма працягнуць. <br/> <p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/> Setup can continue, but some features might be disabled.</p> - + <p>Гэты камп’ютар адпавядае не ўсім патрэбам для ўсталёўкі %1.<br/> + Можна працягнуць усталёўку, але некаторыя магчымасці могуць быць недаступнымі.</p> @@ -3038,7 +3043,7 @@ Output: The file-system resize job has an invalid configuration and will not run. - У задачы па змене памеру файлавай сістэмы хібная канфігурафыя, таму яна не будзе выконвацца. + У задачы па змене памеру файлавай сістэмы хібная канфігурацыя, таму яна не будзе выконвацца. @@ -3486,28 +3491,28 @@ Output: KDE user feedback - + Зваротная сувязь KDE Configuring KDE user feedback. - + Наладка зваротнай сувязі KDE. Error in KDE user feedback configuration. - + Падчас наладкі зваротнай сувязі KDE адбылася памылка. Could not configure KDE user feedback correctly, script error %1. - + Не атрымалася наладзіць зваротную сувязь KDE, памылка скрыпта %1. Could not configure KDE user feedback correctly, Calamares error %1. - + Не атрымалася наладзіць зваротную сувязь KDE, памылка Calamares %1. @@ -3554,7 +3559,7 @@ Output: <html><head/><body><p>Click here to send <span style=" font-weight:600;">no information at all</span> about your installation.</p></body></html> - + <html><head/><body><p>Пстрыкніце сюды, каб не адпраўляць <span style=" font-weight:600;">ніякіх звестак</span> пра вашу ўсталёўку.</p></body></html> @@ -3564,22 +3569,22 @@ Output: Tracking helps %1 to see how often it is installed, what hardware it is installed on and which applications are used. To see what will be sent, please click the help icon next to each area. - + Адсочванне дапамагае праекту %1 бачыць, як часта ён усталёўваецца, на якім абсталяванні ён усталёўваецца, якія праграмы выкарыстоўваюцца. Каб убачыць, што будзе адпраўлена, пстрыкніце па значку ля кожнай вобласці. By selecting this you will send information about your installation and hardware. This information will only be sent <b>once</b> after the installation finishes. - + Абраўшы гэты пункт вы адправіце звесткі пра сваю канфігурацыю ўсталёўкі і ваша абсталяванне. Звесткі адправяцца <b>адзін раз</b> пасля завяршэння ўсталёўкі. By selecting this you will periodically send information about your <b>machine</b> installation, hardware and applications, to %1. - + Абраўшы гэты пункт вы будзеце перыядычна адпраўляць звесткі пра усталёўку, абсталяванне і праграмы вашага <b>камп'ютара</b> на %1. By selecting this you will regularly send information about your <b>user</b> installation, hardware, applications and application usage patterns, to %1. - + Абраўшы гэты пункт вы будзеце перыядычна адпраўляць звесткі пра усталёўку, абсталяванне, праграмы <b>карыстальніка</b> і вобласці іх выкарыстання на %1. @@ -3625,7 +3630,7 @@ Output: Key Column header for key/value - Клавіша + Ключ @@ -3783,7 +3788,7 @@ Output: <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Аўтарскія правы 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Аўтарскія правы 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Шчырыя падзякі <a href="https://calamares.io/team/">камандзе распрацоўкі Calamares</a> і <a href="https://www.transifex.com/calamares/calamares/">камандзе перакладчыкаў Calamares</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> распрацоўваецца пры падтрымцы<br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. @@ -3818,7 +3823,17 @@ Output: development is sponsored by <br/> <a href='http://www.blue-systems.com/'>Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/> + <strong>%2<br/> + for %3</strong><br/><br/> + Аўтарскія правы 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/> + Аўтарскія правы 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/> + Шчырыя падзякі <a href='https://calamares.io/team/'>камандзе распрацоўкі Calamares </a> + і <a href='https://www.transifex.com/calamares/calamares/'> перакладчыкам Calamares</a>.<br/><br/> + <a href='https://calamares.io/'>Calamares</a> + распрацоўваецца пры падтрымцы <br/> + <a href='http://www.blue-systems.com/'>Blue Systems</a> - + Liberating Software. @@ -3832,13 +3847,15 @@ Output: <h1>Languages</h1> </br> The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>. - + <h1>Мовы</h1></br> + Сістэмныя рэгіянальныя налады вызначаюць мову і кадаванне для пэўных элементаў інтэрфейсу загаднага радка. Бягучыя налады <strong>%1</strong>. <h1>Locales</h1> </br> The system locale setting affects the numbers and dates format. The current setting is <strong>%1</strong>. - + <h1>Рэгіянальныя налады</h1></br> + Сістэмныя рэгіянальныя налады вызначаюць фармат нумароў і датаў. Бягучыя налады <strong>%1</strong>. @@ -3866,7 +3883,7 @@ Output: Click your preferred keyboard model to select layout and variant, or use the default one based on the detected hardware. - + Пстрыкніце на пераважную мадэль клавіятуры, каб абраць раскладку і варыянт, альбо выкарыстоўвайце прадвызначаную ў залежнасці ад выяўленага абсталявання. @@ -3881,7 +3898,7 @@ Output: Keyboard Variant - + Варыянт клавіятуры @@ -3894,7 +3911,7 @@ Output: Change - + Змяніць @@ -3932,7 +3949,28 @@ Output: </ul> <p>The vertical scrollbar is adjustable, current width set to 10.</p> - + <h3>%1</h3> + <p>Гэта прыклад файла QML, у якім паказваюцца параметры RichText са зменным змесцівам.</p> + + <p>QML з RichText можа выкарыстоўваць пазнакі HTML. Зменнае змесціва карысна для сэнсарных экранаў.</p> + + <p><b>Гэта паўтлусты тэкст</b></p> + <p><i>Гэта тэкст курсівам</i></p> + <p><u>Гэта падкрэслены</u></p> + <p><center>Гэта выраўнаваны па цэнтры тэкст.</center><s> + <p><s>Гэта закрэслены тэкст</s></p> + + <p>Прыклад кода: + <code>ls -l / +/home</code></p> + + <p><b>Спісы:</b></p> + <ul> + <li>Сістэмы з Intel CPU</li> + <li>Сістэмы з AMD CPU</li> + </ul> + + <p>Вертыкальная паласа пракруткі наладжваецца. Бягучая шырыня - 10.</p> @@ -3945,7 +3983,7 @@ Output: Pick your user name and credentials to login and perform admin tasks - + Абярыце свае імя карыстальніка і ўліковыя даныя для ўваходу і выканання задач адміністратара @@ -3965,12 +4003,12 @@ Output: Login Name - + Лагін If more than one person will use this computer, you can create multiple accounts after installation. - + Калі камп’ютарам карыстаецца некалькі чалавек, то вы можаце стварыць для іх акаўнты пасля завяршэння ўсталёўкі. @@ -3985,7 +4023,7 @@ Output: This name will be used if you make the computer visible to others on a network. - + Назва будзе выкарыстоўвацца для пазначэння камп’ютара ў сетцы. @@ -4005,12 +4043,12 @@ Output: Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals. - + Увядзіце двойчы аднолькавы пароль. Гэта неабходна для таго, каб пазбегнуць памылак. Надзейны пароль павінен складацца з літар, лічбаў, знакаў пунктуацыі. Ён павінен змяшчаць прынамсі 8 знакаў, яго перыядычна трэба змяняць. Validate passwords quality - + Праверка якасці пароляў @@ -4020,12 +4058,12 @@ Output: Log in automatically without asking for the password - + Аўтаматычна ўваходзіць без уводу пароля Reuse user password as root password - + Выкарыстоўваць пароль карыстальніка як пароль адміністратара @@ -4035,22 +4073,22 @@ Output: Choose a root password to keep your account safe. - + Абярыце пароль адміністратара для абароны вашага акаўнта. Root Password - + Пароль адміністратара Repeat Root Password - + Паўтарыце пароль адміністратара Enter the same password twice, so that it can be checked for typing errors. - + Увядзіце пароль двойчы, каб пазбегнуць памылак уводу. @@ -4059,7 +4097,8 @@ Output: <h3>Welcome to the %1 <quote>%2</quote> installer</h3> <p>This program will ask you some questions and set up %1 on your computer.</p> - + <h3>Вітаем у %1, праграме ўсталёўкі<quote>%2</quote> </h3> + <p>Гэтая праграма дапаможа вам усталяваць %1 на ваш камп'ютар.</p> diff --git a/lang/calamares_bg.ts b/lang/calamares_bg.ts index b2a6b2b02..cacab19d0 100644 --- a/lang/calamares_bg.ts +++ b/lang/calamares_bg.ts @@ -6,7 +6,7 @@ The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. - <strong>Среда за начално зареждане</strong> на тази система.<br><br>Старите x86 системи поддържат само <strong>BIOS</strong>.<br>Модерните системи обикновено използват <strong>EFI</strong>, но може също така да използват BIOS, ако са стартирани в режим на съвместимост. + <strong>Средата за начално зареждане</strong> на тази система.<br><br>Старите x86 системи поддържат само <strong>BIOS</strong>.<br>Модерните системи обикновено използват <strong>EFI</strong>, но може също така да използват BIOS, ако са стартирани в режим на съвместимост. @@ -132,7 +132,7 @@ Job failed (%1) - + Задачата се провали (%1) @@ -153,7 +153,7 @@ Example job (%1) - + Примерна задача (%1) @@ -199,7 +199,7 @@ Main script file %1 for python job %2 is not readable. - Файлът на главен скрипт %1 за python задача %2 не се чете. + Файла на главен скрипт %1 за python задача %2 не се чете. @@ -3755,12 +3755,12 @@ Output: <h1>Welcome to the Calamares installer for %1.</h1> - <h1>Добре дошли при инсталатора Calamares на %1.</h1> + <h1>Добре дошли в инсталатора Calamares за %1.</h1> <h1>Welcome to the %1 installer.</h1> - <h1>Добре дошли при инсталатора на %1.</h1> + <h1>Добре дошли в инсталатора на %1.</h1> diff --git a/lang/calamares_bn.ts b/lang/calamares_bn.ts index 6887bdf28..06b696140 100644 --- a/lang/calamares_bn.ts +++ b/lang/calamares_bn.ts @@ -3337,7 +3337,7 @@ Output: Set password for user %1 - ব্যবহারকারীর জন্য গুপ্ত-সংকেত নির্ধারণ করুন % 1 + ব্যবহারকারীর জন্য গুপ্ত-সংকেত নির্ধারণ করুন %1 @@ -3352,7 +3352,7 @@ Output: rootMountPoint is %1 - রুটমাউন্টপয়েন্টটি % 1 + রুটমাউন্টপয়েন্টটি %1 @@ -3367,7 +3367,7 @@ Output: Cannot set password for user %1. - % 1 ব্যবহারকারীর জন্য পাসওয়ার্ড নির্ধারণ করা যাচ্ছে না। + %1 ব্যবহারকারীর জন্য পাসওয়ার্ড নির্ধারণ করা যাচ্ছে না। diff --git a/lang/calamares_ca.ts b/lang/calamares_ca.ts index 07df2503f..49d14be33 100644 --- a/lang/calamares_ca.ts +++ b/lang/calamares_ca.ts @@ -619,7 +619,7 @@ L'instal·lador es tancarà i tots els canvis es perdran. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Aquest dispositiu d'emmagatzematge ja té un sistema operatiu, però la taula de particions <strong>%1</strong> és diferent de la necessària: <strong>%2</strong>.<br/> diff --git a/lang/calamares_cs_CZ.ts b/lang/calamares_cs_CZ.ts index 2ceef9619..7f63af78e 100644 --- a/lang/calamares_cs_CZ.ts +++ b/lang/calamares_cs_CZ.ts @@ -623,7 +623,7 @@ Instalační program bude ukončen a všechny změny ztraceny. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Na tomto úložném zařízení se už nachází operační systém, ale tabulka rozdělení <strong>%1</strong> je jiná než potřebná <strong>%2</strong>.<br/> diff --git a/lang/calamares_da.ts b/lang/calamares_da.ts index e2fc21085..e5593c7d0 100644 --- a/lang/calamares_da.ts +++ b/lang/calamares_da.ts @@ -619,17 +619,17 @@ Installationsprogrammet vil stoppe og alle ændringer vil gå tabt. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Lagerenheden har allerede et styresystem på den men partitionstabellen <strong>%1</strong> er ikke magen til den nødvendige <strong>%2</strong>.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Lagerenhden har en af sine partitioner <strong>monteret</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Lagringsenheden er en del af en <strong>inaktiv RAID</strong>-enhed. diff --git a/lang/calamares_de.ts b/lang/calamares_de.ts index 6a972aca8..8e8e458c1 100644 --- a/lang/calamares_de.ts +++ b/lang/calamares_de.ts @@ -619,17 +619,17 @@ Dies wird das Installationsprogramm beenden und alle Änderungen gehen verloren. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Auf diesem Speichergerät befindet sich bereits ein Betriebssystem, aber die Partitionstabelle <strong>%1</strong> unterscheidet sich von den erforderlichen <strong>%2</strong><br/> This storage device has one of its partitions <strong>mounted</strong>. - + Bei diesem Speichergerät ist eine seiner Partitionen <strong>eingehängt</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Dieses Speichergerät ist ein Teil eines <strong>inaktiven RAID</strong>-Geräts. @@ -2868,7 +2868,7 @@ Ausgabe: Directory not found - + Verzeichnis nicht gefunden diff --git a/lang/calamares_en.ts b/lang/calamares_en.ts index 88c923a96..0ef707a3d 100644 --- a/lang/calamares_en.ts +++ b/lang/calamares_en.ts @@ -4,17 +4,17 @@ BootInfoWidget - + The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. - + This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. - + This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. @@ -533,7 +533,7 @@ The installer will quit and all changes will be lost. <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. - + Reuse %1 as home partition for %2. Reuse %1 as home partition for %2. @@ -558,101 +558,101 @@ The installer will quit and all changes will be lost. <strong>Select a partition to install on</strong> - + An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. - + The EFI system partition at %1 will be used for starting %2. The EFI system partition at %1 will be used for starting %2. - + EFI system partition: EFI system partition: - + This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - - - - + + + + <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. - - - - + + + + <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. - - - - + + + + <strong>Replace a partition</strong><br/>Replaces a partition with %1. <strong>Replace a partition</strong><br/>Replaces a partition with %1. - + This storage device has %1 on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device has %1 on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + This storage device already has an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device already has an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + This storage device has multiple operating systems on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device has multiple operating systems on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + This storage device has one of its partitions <strong>mounted</strong>. This storage device has one of its partitions <strong>mounted</strong>. - + This storage device is a part of an <strong>inactive RAID</strong> device. This storage device is a part of an <strong>inactive RAID</strong> device. - + No Swap No Swap - + Reuse Swap Reuse Swap - + Swap (no Hibernate) Swap (no Hibernate) - + Swap (with Hibernate) Swap (with Hibernate) - + Swap to file Swap to file @@ -720,12 +720,12 @@ The installer will quit and all changes will be lost. Config - + Set keyboard model to %1.<br/> Set keyboard model to %1.<br/> - + Set keyboard layout to %1/%2. Set keyboard layout to %1/%2. @@ -810,47 +810,47 @@ The installer will quit and all changes will be lost. <h1>Welcome to the %1 installer</h1> - + Your username is too long. Your username is too long. - + '%1' is not allowed as username. '%1' is not allowed as username. - + Your username must start with a lowercase letter or underscore. Your username must start with a lowercase letter or underscore. - + Only lowercase letters, numbers, underscore and hyphen are allowed. Only lowercase letters, numbers, underscore and hyphen are allowed. - + Your hostname is too short. Your hostname is too short. - + Your hostname is too long. Your hostname is too long. - + '%1' is not allowed as hostname. '%1' is not allowed as hostname. - + Only letters, numbers, underscore and hyphen are allowed. Only letters, numbers, underscore and hyphen are allowed. - + Your passwords do not match! Your passwords do not match! @@ -1018,29 +1018,39 @@ The installer will quit and all changes will be lost. CreateUserJob - + Create user %1 Create user %1 - + Create user <strong>%1</strong>. Create user <strong>%1</strong>. - + Creating user %1. Creating user %1. - - Cannot create sudoers file for writing. - Cannot create sudoers file for writing. + + Preserving home directory + - - Cannot chmod sudoers file. - Cannot chmod sudoers file. + + Creating user %1 + Creating user %1. {1?} + + + + Configuring user %1 + + + + + Setting file permissions + @@ -1243,7 +1253,7 @@ The installer will quit and all changes will be lost. Flags: - + Mountpoint already in use. Please select another one. Mountpoint already in use. Please select another one. @@ -1558,23 +1568,10 @@ The installer will quit and all changes will be lost. Script - - KeyboardPage - - - Set keyboard model to %1.<br/> - Set keyboard model to %1.<br/> - - - - Set keyboard layout to %1/%2. - Set keyboard layout to %1/%2. - - KeyboardQmlViewStep - + Keyboard Keyboard @@ -1582,7 +1579,7 @@ The installer will quit and all changes will be lost. KeyboardViewStep - + Keyboard Keyboard @@ -1664,59 +1661,59 @@ The installer will quit and all changes will be lost. LicenseWidget - + URL: %1 URL: %1 - + <strong>%1 driver</strong><br/>by %2 %1 is an untranslatable product name, example: Creative Audigy driver <strong>%1 driver</strong><br/>by %2 - + <strong>%1 graphics driver</strong><br/><font color="Grey">by %2</font> %1 is usually a vendor name, example: Nvidia graphics driver <strong>%1 graphics driver</strong><br/><font color="Grey">by %2</font> - + <strong>%1 browser plugin</strong><br/><font color="Grey">by %2</font> <strong>%1 browser plugin</strong><br/><font color="Grey">by %2</font> - + <strong>%1 codec</strong><br/><font color="Grey">by %2</font> <strong>%1 codec</strong><br/><font color="Grey">by %2</font> - + <strong>%1 package</strong><br/><font color="Grey">by %2</font> <strong>%1 package</strong><br/><font color="Grey">by %2</font> - + <strong>%1</strong><br/><font color="Grey">by %2</font> <strong>%1</strong><br/><font color="Grey">by %2</font> - + File: %1 File: %1 - + Hide license text Hide license text - + Show the license text Show the license text - + Open license agreement in browser. Open license agreement in browser. @@ -1724,18 +1721,18 @@ The installer will quit and all changes will be lost. LocalePage - + Region: Region: - + Zone: Zone: - - + + &Change... &Change... @@ -2057,188 +2054,215 @@ The installer will quit and all changes will be lost. The password contains forbidden words in some form The password contains forbidden words in some form - - - The password contains less than %1 digits - The password contains less than %1 digits - The password contains too few digits The password contains too few digits - - - The password contains less than %1 uppercase letters - The password contains less than %1 uppercase letters - The password contains too few uppercase letters The password contains too few uppercase letters - - - The password contains less than %1 lowercase letters - The password contains less than %1 lowercase letters - The password contains too few lowercase letters The password contains too few lowercase letters - - The password contains less than %1 non-alphanumeric characters - The password contains less than %1 non-alphanumeric characters - - - + The password contains too few non-alphanumeric characters The password contains too few non-alphanumeric characters - - The password is shorter than %1 characters - The password is shorter than %1 characters - - - + The password is too short The password is too short - - The password is just rotated old one - The password is just rotated old one - - - - The password contains less than %1 character classes - The password contains less than %1 character classes - - - + The password does not contain enough character classes The password does not contain enough character classes - - The password contains more than %1 same characters consecutively - The password contains more than %1 same characters consecutively - - - + The password contains too many same characters consecutively The password contains too many same characters consecutively - - The password contains more than %1 characters of the same class consecutively - The password contains more than %1 characters of the same class consecutively - - - + The password contains too many characters of the same class consecutively The password contains too many characters of the same class consecutively - - - The password contains monotonic sequence longer than %1 characters - The password contains monotonic sequence longer than %1 characters + + + The password contains fewer than %n digits + + + + + + + + The password contains fewer than %n uppercase letters + + + + + + + + The password contains fewer than %n lowercase letters + + + + + + + + The password contains fewer than %n non-alphanumeric characters + + + + + + + + The password is shorter than %n characters + + + + + + The password is a rotated version of the previous one + + + + + The password contains fewer than %n character classes + + + + + + + + The password contains more than %n same characters consecutively + + + + + + + + The password contains more than %n characters of the same class consecutively + + + + + + + The password contains monotonic sequence longer than %n characters + + + + + + + The password contains too long of a monotonic character sequence The password contains too long of a monotonic character sequence - + No password supplied No password supplied - + Cannot obtain random numbers from the RNG device Cannot obtain random numbers from the RNG device - + Password generation failed - required entropy too low for settings Password generation failed - required entropy too low for settings - + The password fails the dictionary check - %1 The password fails the dictionary check - %1 - + The password fails the dictionary check The password fails the dictionary check - + Unknown setting - %1 Unknown setting - %1 - + Unknown setting Unknown setting - + Bad integer value of setting - %1 Bad integer value of setting - %1 - + Bad integer value Bad integer value - + Setting %1 is not of integer type Setting %1 is not of integer type - + Setting is not of integer type Setting is not of integer type - + Setting %1 is not of string type Setting %1 is not of string type - + Setting is not of string type Setting is not of string type - + Opening the configuration file failed Opening the configuration file failed - + The configuration file is malformed The configuration file is malformed - + Fatal failure Fatal failure - + Unknown error Unknown error - + Password is empty Password is empty @@ -2572,117 +2596,117 @@ The installer will quit and all changes will be lost. PartitionViewStep - + Gathering system information... Gathering system information... - + Partitions Partitions - + Install %1 <strong>alongside</strong> another operating system. Install %1 <strong>alongside</strong> another operating system. - + <strong>Erase</strong> disk and install %1. <strong>Erase</strong> disk and install %1. - + <strong>Replace</strong> a partition with %1. <strong>Replace</strong> a partition with %1. - + <strong>Manual</strong> partitioning. <strong>Manual</strong> partitioning. - + Install %1 <strong>alongside</strong> another operating system on disk <strong>%2</strong> (%3). Install %1 <strong>alongside</strong> another operating system on disk <strong>%2</strong> (%3). - + <strong>Erase</strong> disk <strong>%2</strong> (%3) and install %1. <strong>Erase</strong> disk <strong>%2</strong> (%3) and install %1. - + <strong>Replace</strong> a partition on disk <strong>%2</strong> (%3) with %1. <strong>Replace</strong> a partition on disk <strong>%2</strong> (%3) with %1. - + <strong>Manual</strong> partitioning on disk <strong>%1</strong> (%2). <strong>Manual</strong> partitioning on disk <strong>%1</strong> (%2). - + Disk <strong>%1</strong> (%2) Disk <strong>%1</strong> (%2) - + Current: Current: - + After: After: - + No EFI system partition configured No EFI system partition configured - + An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a FAT32 filesystem with the <strong>%3</strong> flag enabled and mount point <strong>%2</strong>.<br/><br/>You can continue without setting up an EFI system partition but your system may fail to start. An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a FAT32 filesystem with the <strong>%3</strong> flag enabled and mount point <strong>%2</strong>.<br/><br/>You can continue without setting up an EFI system partition but your system may fail to start. - + An EFI system partition is necessary to start %1.<br/><br/>A partition was configured with mount point <strong>%2</strong> but its <strong>%3</strong> flag is not set.<br/>To set the flag, go back and edit the partition.<br/><br/>You can continue without setting the flag but your system may fail to start. An EFI system partition is necessary to start %1.<br/><br/>A partition was configured with mount point <strong>%2</strong> but its <strong>%3</strong> flag is not set.<br/>To set the flag, go back and edit the partition.<br/><br/>You can continue without setting the flag but your system may fail to start. - + EFI system partition flag not set EFI system partition flag not set - + Option to use GPT on BIOS Option to use GPT on BIOS - + A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.<br/><br/>To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the <strong>bios_grub</strong> flag enabled.<br/><br/>An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT. A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.<br/><br/>To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the <strong>bios_grub</strong> flag enabled.<br/><br/>An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT. - + Boot partition not encrypted Boot partition not encrypted - + A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.<br/><br/>There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.<br/>You may continue if you wish, but filesystem unlocking will happen later during system startup.<br/>To encrypt the boot partition, go back and recreate it, selecting <strong>Encrypt</strong> in the partition creation window. A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.<br/><br/>There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.<br/>You may continue if you wish, but filesystem unlocking will happen later during system startup.<br/>To encrypt the boot partition, go back and recreate it, selecting <strong>Encrypt</strong> in the partition creation window. - + has at least one disk device available. has at least one disk device available. - + There are no partitions to install on. There are no partitions to install on. @@ -2842,13 +2866,8 @@ Output: swap - - Default Keyboard Model - Default Keyboard Model - - - - + + Default Default @@ -3232,29 +3251,29 @@ Output: SetKeyboardLayoutJob - + Set keyboard model to %1, layout to %2-%3 Set keyboard model to %1, layout to %2-%3 - + Failed to write keyboard configuration for the virtual console. Failed to write keyboard configuration for the virtual console. - - - + + + Failed to write to %1 Failed to write to %1 - + Failed to write keyboard configuration for X11. Failed to write keyboard configuration for X11. - + Failed to write keyboard configuration to existing /etc/default directory. Failed to write keyboard configuration to existing /etc/default directory. @@ -3423,6 +3442,43 @@ Output: Cannot open /etc/timezone for writing + + SetupGroupsJob + + + Preparing groups. + + + + + + Could not create groups in target system + + + + + These groups are missing in the target system: %1 + + + + + SetupSudoJob + + + Configure <pre>sudo</pre> users. + + + + + Cannot chmod sudoers file. + Cannot chmod sudoers file. + + + + Cannot create sudoers file for writing. + Cannot create sudoers file for writing. + + ShellProcessJob @@ -3443,12 +3499,12 @@ Output: SummaryPage - + This is an overview of what will happen once you start the setup procedure. This is an overview of what will happen once you start the setup procedure. - + This is an overview of what will happen once you start the install procedure. This is an overview of what will happen once you start the install procedure. diff --git a/lang/calamares_es.ts b/lang/calamares_es.ts index c579cd752..b4104670d 100644 --- a/lang/calamares_es.ts +++ b/lang/calamares_es.ts @@ -162,12 +162,12 @@ Para configurar el arranque desde un entorno BIOS, este instalador debe instalar Run command '%1' in target system. - Ejecutar el comando '% 1' en el sistema de destino. + Ejecutar el comando '%1' en el sistema de destino. Run command '%1'. - Ejecutar el comando '% 1'. + Ejecutar el comando '%1'. @@ -1120,7 +1120,7 @@ Saldrá del instalador y se perderán todos los cambios. This device has a <strong>%1</strong> partition table. - Este dispositivo tiene un <strong>% 1 </ strong> tabla de particiones. + Este dispositivo tiene un <strong>%1</strong> tabla de particiones. diff --git a/lang/calamares_es_MX.ts b/lang/calamares_es_MX.ts index 00c1c2188..9e9e17b94 100644 --- a/lang/calamares_es_MX.ts +++ b/lang/calamares_es_MX.ts @@ -1080,17 +1080,17 @@ El instalador terminará y se perderán todos los cambios. Deactivate volume group named %1. - Desactivar el grupo de volúmenes llamado%1. + Desactivar el grupo de volúmenes llamado %1. Deactivate volume group named <strong>%1</strong>. - Desactivar el grupo de volúmenes llamado<strong>% 1</strong>. + Desactivar el grupo de volúmenes llamado<strong>%1</strong>. The installer failed to deactivate a volume group named %1. - El instalador no pudo desactivar un grupo de volúmenes llamado%1. + El instalador no pudo desactivar un grupo de volúmenes llamado %1. @@ -1330,7 +1330,7 @@ El instalador terminará y se perderán todos los cambios. <h1>All done.</h1><br/>%1 has been set up on your computer.<br/>You may now start using your new system. - <h1>Todo listo.</h1><br/>% 1 se ha configurado en su computadora. <br/>Ahora puede comenzar a usar su nuevo sistema. + <h1>Todo listo.</h1><br/>%1 se ha configurado en su computadora. <br/>Ahora puede comenzar a usar su nuevo sistema. @@ -2198,7 +2198,7 @@ El instalador terminará y se perderán todos los cambios. Setting %1 is not of integer type - Ajuste de % 1 no es de tipo entero + Ajuste de %1 no es de tipo entero @@ -3260,7 +3260,7 @@ Salida Set flags on partition %1. - Establecer indicadores en la partición% 1. + Establecer indicadores en la partición %1. @@ -3335,7 +3335,7 @@ Salida The installer failed to set flags on partition %1. - El instalador no pudo establecer indicadores en la partición% 1. + El instalador no pudo establecer indicadores en la partición %1. @@ -3530,12 +3530,12 @@ Salida Could not configure machine feedback correctly, script error %1. - No se pudo configurar correctamente la retroalimentación de la máquina, error de script% 1. + No se pudo configurar correctamente la retroalimentación de la máquina, error de script %1. Could not configure machine feedback correctly, Calamares error %1. - No se pudo configurar la retroalimentación de la máquina correctamente, Calamares error% 1. + No se pudo configurar la retroalimentación de la máquina correctamente, Calamares error %1. diff --git a/lang/calamares_fi_FI.ts b/lang/calamares_fi_FI.ts index e3ff2229e..1bf0d09cc 100644 --- a/lang/calamares_fi_FI.ts +++ b/lang/calamares_fi_FI.ts @@ -619,17 +619,17 @@ Asennusohjelma sulkeutuu ja kaikki muutoksesi katoavat. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Tässä kiintolevyssä on jo käyttöjärjestelmä, mutta osiotaulukko <strong>%1</strong> on erilainen kuin tarvittava <strong>%2</strong>.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Tähän kiintolevyyn on <strong>asennettu</strong> yksi osioista. This storage device is a part of an <strong>inactive RAID</strong> device. - + Tämä kiintolevy on osa <strong>passiivista RAID</strong> -laitetta. diff --git a/lang/calamares_fur.ts b/lang/calamares_fur.ts index 7575c0e2a..d2f3a8127 100644 --- a/lang/calamares_fur.ts +++ b/lang/calamares_fur.ts @@ -153,7 +153,7 @@ Example job (%1) - Operazion di esempli (%1) + Lavôr di esempli (%1) @@ -189,7 +189,7 @@ Working directory %1 for python job %2 is not readable. - No si rive a lei la cartele di lavôr %1 pe ativitât di python %2. + No si rive a lei la cartele di lavôr %1 pe operazion di python %2. @@ -199,7 +199,7 @@ Main script file %1 for python job %2 is not readable. - No si rive a lei il file di script principâl %1 pe ativitât di python %2. + No si rive a lei il file di script principâl %1 pe operazion di python %2. @@ -2258,7 +2258,7 @@ Il program di instalazion al jessarà e dutis lis modifichis a laran pierdudis.< TextLabel - + EticheteTest @@ -2366,7 +2366,7 @@ Il program di instalazion al jessarà e dutis lis modifichis a laran pierdudis.< <small>Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals.</small> - <small>Inserìs la stesse password dôs voltis, in mût di evitâ erôrs di scriture. Une buine password e contignarà un miscliç di letaris, numars e puntuazions, e sarà lungje almancul vot caratars, e si scugnarà cambiâle a intervai regolârs.</small> + <small>Inserìs la stesse password dôs voltis, in mût di evitâ erôrs di batidure. Une buine password e contignarà un miscliç di letaris, numars e puntuazions, e sarà lungje almancul vot caratars, e si scugnarà cambiâle a intervai regolârs.</small> @@ -2791,7 +2791,7 @@ Output: Bad parameters for process job call. - Parametris sbaliâts par processâ la clamade dal lavôr. + Parametris sbaliâts par processâ la clamade de operazion. @@ -2979,24 +2979,24 @@ Output: %1 system partition (%2) - + %1 partizion di sisteme (%2) <strong>%4</strong><br/><br/>The partition %1 is too small for %2. Please select a partition with capacity at least %3 GiB. - + <strong>%4</strong><br/><br/>La partizion %1 e je masse piçule par %2. Selezione une partizion cun almancul %3 GiB di capacitât. <strong>%2</strong><br/><br/>An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. - + <strong>%2</strong><br/><br/>No si rive a cjatâ di nissune bande su cheste machine une partizion di sisteme EFI. Par plasê torne indaûr e dopre il partizionament manuâl par configurâ %1. <strong>%3</strong><br/><br/>%1 will be installed on %2.<br/><font color="red">Warning: </font>all data on partition %2 will be lost. - + <strong>%3</strong><br/><br/>Si instalarà %1 su %2.<br/><font color="red">Atenzion: </font>ducj i dâts de partizion %2 a laran pierdûts. @@ -3015,7 +3015,8 @@ Output: <p>This computer does not satisfy the minimum requirements for installing %1.<br/> Installation cannot continue.</p> - + <p>Chest computer nol sodisfe i recuisîts minims pe instalazion di %1.<br/> + La instalazion no pues continuâ.</p> @@ -3030,27 +3031,27 @@ Output: Resize Filesystem Job - + Operazion di ridimensionament dal filesystem Invalid configuration - + Configurazion no valide The file-system resize job has an invalid configuration and will not run. - + La operazion di ridimensionament dal filesystem e à une configurazion no valide e no vignarà eseguide. KPMCore not Available - + KPMCore no disponibil Calamares cannot start KPMCore for the file-system resize job. - + Calamares nol rive a inviâ KPMCore pe operazion di ridimensionament dal filesystem. @@ -3059,39 +3060,39 @@ Output: Resize Failed - + Ridimensionament falît The filesystem %1 could not be found in this system, and cannot be resized. - + Nol è stât pussibil cjatâ in chest sisteme il filesystem %1 e duncje nol pues jessi ridimensionât. The device %1 could not be found in this system, and cannot be resized. - + Nol è stât pussibil cjatâ in chest sisteme il dispositîf %1 e duncje nol pues jessi ridimensionât. The filesystem %1 cannot be resized. - + Impussibil ridimensionâ il filesystem %1. The device %1 cannot be resized. - + Impussibil ridimensionâ il dispositîf %1. The filesystem %1 must be resized, but cannot. - + Si scugne ridimensionâ il filesystem %1, ma no si rive. The device %1 must be resized, but cannot - + Si scugne ridimensionâ il filesystem %1, ma no si rive. @@ -3099,22 +3100,22 @@ Output: Resize partition %1. - + Ridimensionâ partizion %1 Resize <strong>%2MiB</strong> partition <strong>%1</strong> to <strong>%3MiB</strong>. - + Ridimensionâ la partizion <strong>%1</strong> di <strong>%2MiB</strong> a <strong>%3MiB</strong>. Resizing %2MiB partition %1 to %3MiB. - + Ridimensionâ la partizion %1 di %2MiB a %3MiB. The installer failed to resize partition %1 on disk '%2'. - + Il program di instalazion nol è rivât a ridimensionâ la partizion %1 sul disc '%2'. @@ -3131,17 +3132,17 @@ Output: Resize volume group named %1 from %2 to %3. - + Ridimensionâ il grup di volums clamât %1 di %2 a %3. Resize volume group named <strong>%1</strong> from <strong>%2</strong> to <strong>%3</strong>. - + Ridimensionâ il grup di volums clamât <strong>%1</strong> di <strong>%2</strong> a <strong>%3</strong>. The installer failed to resize a volume group named '%1'. - + Il program di instalazion nol è rivât a ridimensionâ un grup di volums clamât '%1'. @@ -3149,12 +3150,12 @@ Output: For best results, please ensure that this computer: - + Par otignî i miôrs risultâts, siguriti che chest computer: System requirements - + Recuisîts di sisteme @@ -3190,12 +3191,12 @@ Output: Scanning storage devices... - + Scandai dai dispositîfs di memorie... Partitioning - + Partizionament @@ -3203,29 +3204,29 @@ Output: Set hostname %1 - + Stabilî il non-host a %1 Set hostname <strong>%1</strong>. - + Stabilî il non-host a <strong>%1</strong>. Setting hostname %1. - + Daûr a stabilî il non-host a %1. Internal Error - + Erôr interni Cannot write hostname to target system - + Impussibil scrivi il non-host sul sisteme di destinazion @@ -3233,29 +3234,29 @@ Output: Set keyboard model to %1, layout to %2-%3 - + Stabilî il model di tastiere a %1, disposizion a %2-%3 Failed to write keyboard configuration for the virtual console. - + No si è rivâts a scrivi la configurazion de tastiere pe console virtuâl. Failed to write to %1 - + No si è rivâts a scrivi su %1 Failed to write keyboard configuration for X11. - + No si è rivâts a scrivi la configurazion de tastiere par X11. Failed to write keyboard configuration to existing /etc/default directory. - + No si è rivâts a scrivi la configurazion de tastiere te cartele esistente /etc/default . @@ -3346,42 +3347,42 @@ Output: Set password for user %1 - + Stabilî la password pal utent %1 Setting password for user %1. - + Daûr a stabilî la password pal utent %1. Bad destination system path. - + Percors di sisteme de destinazion sbaliât. rootMountPoint is %1 - + Il rootMountPoint (pont di montaç de lidrîs) al è %1 Cannot disable root account. - + Impussibil disabilitâ l'account di root. passwd terminated with error code %1. - + passwd terminât cun codiç di erôr %1. Cannot set password for user %1. - + Impussibil stabilî la password pal utent %1. usermod terminated with error code %1. - + usermod terminât cun codiç di erôr %1. @@ -3389,37 +3390,37 @@ Output: Set timezone to %1/%2 - + Meti il fûs orari su %1/%2 Cannot access selected timezone path. - + Impussibil acedi al percors dal fûs orari selezionât. Bad path: %1 - + Percors no valit: %1 Cannot set timezone. - + Impussibil stabilî il fûs orari. Link creation failed, target: %1; link name: %2 - + Creazion dal colegament falide, destinazion: %1; non colegament: %2 Cannot set timezone, - + Impussibil stabilî il fûs orari, Cannot open /etc/timezone for writing - + Impussibil vierzi /etc/timezone pe scriture @@ -3427,7 +3428,7 @@ Output: Shell Processes Job - + Operazion dai procès de shell @@ -3436,7 +3437,7 @@ Output: %L1 / %L2 slide counter, %1 of %2 (numeric) - + %L1 / %L2 @@ -3444,12 +3445,12 @@ Output: This is an overview of what will happen once you start the setup procedure. - + Cheste e je une panoramiche di ce che al sucedarà une volte inviade la procedure di configurazion. This is an overview of what will happen once you start the install procedure. - + Cheste e je une panoramiche di ce che al sucedarà une volte inviade la procedure di instalazion. @@ -3457,7 +3458,7 @@ Output: Summary - + Sintesi @@ -3465,22 +3466,22 @@ Output: Installation feedback - + Opinion su la instalazion Sending installation feedback. - + Daûr a inviâ la opinion su la instalazion. Internal error in install-tracking. - + Erôr interni in install-tracking. HTTP request timed out. - + Richieste HTTP scjadude. @@ -3488,28 +3489,28 @@ Output: KDE user feedback - + Opinion dal utent di KDE Configuring KDE user feedback. - + Daûr a configurâ la opinione dal utent di KDE. Error in KDE user feedback configuration. - + Erôr te configurazion de opinion dal utent di KDE. Could not configure KDE user feedback correctly, script error %1. - + Nol è stât pussibil configurâ in maniere juste la opinion dal utent di KDE, erôr di script %1. Could not configure KDE user feedback correctly, Calamares error %1. - + Nol è stât pussibil configurâ in maniere juste la opinion dal utent di KDE, erôr di Calamares %1. @@ -3517,28 +3518,28 @@ Output: Machine feedback - + Opinion su la machine Configuring machine feedback. - + Daûr a configurâ la opinion su la machine. Error in machine feedback configuration. - + Erôr inte configurazion de opinion su la machine. Could not configure machine feedback correctly, script error %1. - + Nol è stât pussibil configurâ in maniere juste la opinion su la machine, erôr di script %1. Could not configure machine feedback correctly, Calamares error %1. - + Nol è stât pussibil configurâ in maniere juste la opinion su la machine, erôr di Calamares %1. @@ -3551,37 +3552,37 @@ Output: Placeholder - + Segnepuest <html><head/><body><p>Click here to send <span style=" font-weight:600;">no information at all</span> about your installation.</p></body></html> - + <html><head/><body><p>Fâs clic achì par <span style=" font-weight:600;">no inviâ nissune informazion</span> su la tô instalazion.</p></body></html> <html><head/><body><p><a href="placeholder"><span style=" text-decoration: underline; color:#2980b9;">Click here for more information about user feedback</span></a></p></body></html> - + <html><head/><body><p><a href="placeholder"><span style=" text-decoration: underline; color:#2980b9;">Fâs clic achì par vê plui informazions su lis opinions dai utents</span></a></p></body></html> Tracking helps %1 to see how often it is installed, what hardware it is installed on and which applications are used. To see what will be sent, please click the help icon next to each area. - + Tignî i indizis al jude %1 a viodi trop dispès che al ven instalât, in cuâl hardware e ce aplicazions che a vegnin dopradis. Par viodi ce che al ven inviât, fâs clic su pe icone di jutori dongje a ogni aree. By selecting this you will send information about your installation and hardware. This information will only be sent <b>once</b> after the installation finishes. - + Selezionant chest tu inviarâs informazions sul to hardware e su la tô instalazion. Cheste informazion e vignarà mandade dome <b>une volte</b>, dopo finide la instalazion. By selecting this you will periodically send information about your <b>machine</b> installation, hardware and applications, to %1. - + Selezionant chest tu mandarâs informazions in mût periodic a %1 su la instalazion, l'hardware e lis aplicazions de tô <b>machine</b>. By selecting this you will regularly send information about your <b>user</b> installation, hardware, applications and application usage patterns, to %1. - + Selezionant chest tu mandarâs cun regolaritât informazions a %1 su la instalazion, l'hardware, lis aplicazions e modei di ûs de aplicazion dal tô <b>utent</b>. @@ -3589,7 +3590,7 @@ Output: Feedback - + Opinion @@ -3597,12 +3598,12 @@ Output: <small>If more than one person will use this computer, you can create multiple accounts after setup.</small> - + <small>Se chest computer al vignarà doprât di plui di une persone, si pues creâ plui accounts dopo vê completade la configurazion.</small> <small>If more than one person will use this computer, you can create multiple accounts after installation.</small> - + <small>Se chest computer al vignarà doprât di plui di une persone, si pues creâ plui accounts dopo vê completade la instalazion.</small> @@ -3610,7 +3611,7 @@ Output: Users - + Utents @@ -3618,7 +3619,7 @@ Output: Users - + Utents @@ -3627,13 +3628,13 @@ Output: Key Column header for key/value - + Clâf Value Column header for key/value - + Valôr @@ -3646,22 +3647,22 @@ Output: List of Physical Volumes - + Liste di volums fisics Volume Group Name: - + Non dal grup di volums: Volume Group Type: - + Gjenar dal grup di volums: Physical Extent Size: - + Dimension de estension fisiche: @@ -3671,22 +3672,22 @@ Output: Total Size: - + Dimension totâl: Used Size: - + Dimension doprade: Total Sectors: - + Setôrs totâi: Quantity of LVs: - + Cuantitât di VLs: @@ -3700,92 +3701,92 @@ Output: Select application and system language - + Selezionâ lenghe di sisteme e di aplicazions &About - + &Informazions Open donations website - + Vierç il sît web pes donazions &Donate - + &Done Open help and support website - + Vierç il sît web pal jutori e pal supuart &Support - + &Supuart Open issues and bug-tracking website - + Vierç il sît web sui problemis e lis segnalazions/indizis sui erôrs &Known issues - + &Problemis cognossûts Open release notes website - + Vierç il sît web des notis di publicazion &Release notes - + &Notis di publicazion <h1>Welcome to the Calamares setup program for %1.</h1> - + <h1>Benvignûts sul program di configurazion Calamares par %1.</h1> <h1>Welcome to %1 setup.</h1> - + <h1>Benvignûts te configurazion di %1.</h1> <h1>Welcome to the Calamares installer for %1.</h1> - + <h1>Benvignûts sul program di instalazion Calamares par %1.</h1> <h1>Welcome to the %1 installer.</h1> - + <h1>Benvignûts sul program di instalazion di %1.</h1> %1 support - + Supuart di %1 About %1 setup - + Informazions su la configurazion di %1 About %1 installer - + Informazion su la instalazion di %1 <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/><strong>%2<br/>par %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Gracie a <a href="https://calamares.io/team/">il grup di Calamares</a> e al <a href="https://www.transifex.com/calamares/calamares/">grup di tradutôrs di Calamares</a>.<br/><br/>Il disvilup di <a href="https://calamares.io/">Calamares</a> al è patrocinât di <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. @@ -3793,7 +3794,7 @@ Output: Welcome - + Benvignûts @@ -3801,7 +3802,7 @@ Output: Welcome - + Benvignûts @@ -3820,12 +3821,23 @@ Output: development is sponsored by <br/> <a href='http://www.blue-systems.com/'>Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/> + <strong>%2<br/> + par %3</strong><br/><br/> + Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/> + Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/> + Gracie a <a href='https://calamares.io/team/'>il grup di Calamares</a> + e al <a href='https://www.transifex.com/calamares/calamares/'>grup di tradutôrs + di Calamares</a>.<br/><br/> + Il disvilup di + <a href='https://calamares.io/'>Calamares</a> al è patrocinât di <br/> + <a href='http://www.blue-systems.com/'>Blue Systems</a> - + Liberating Software. Back - + Indaûr @@ -3834,18 +3846,20 @@ Output: <h1>Languages</h1> </br> The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>. - + <h1>Lenghis</h1> </br> + La impostazion di localizazion dal sisteme e influence la lenghe e la cumbinazion di caratars par cualchi element de interface utent a rie di comant. La impostazion atuâl e je <strong>%1</strong>. <h1>Locales</h1> </br> The system locale setting affects the numbers and dates format. The current setting is <strong>%1</strong>. - + <h1>Localitâts</h1> </br> + La impostazions di localizazion dal sisteme e influence il formât des datis e dai numars. La impostazion atuâl e je <strong>%1</strong>. Back - + Indaûr @@ -3853,42 +3867,42 @@ Output: Keyboard Model - + Model di tastiere Layouts - + Disposizions Keyboard Layout - + Disposizion di tastiere Click your preferred keyboard model to select layout and variant, or use the default one based on the detected hardware. - + Fâs clic sul model di tastiere preferît par selezionâ la disposizion e la variante, o dopre chel predefinît basât sul hardware rilevât. Models - + Modei Variants - + Variantis Keyboard Variant - + Variante di tastiere Test your keyboard - + Prove la tastiere @@ -3896,7 +3910,7 @@ Output: Change - + Cambie @@ -3905,7 +3919,8 @@ Output: <h3>%1</h3> <p>These are example release notes.</p> - + <h3>%1</h3> + <p>Chescj a son esemplis di notis di publicazion.</p> @@ -3933,12 +3948,32 @@ Output: </ul> <p>The vertical scrollbar is adjustable, current width set to 10.</p> - + <h3>%1</h3> + <p>Chest esempli di file QML, al mostre lis opzions in test formatât cun contignût che si pues dai une passade.</p> + + <p>Il QML cun test formatât al pues doprâ etichetis HTML, il contignût che si pues scori al è util pai touchscreens.</p> + + <p><b>Chest al è test in neret</b></p> + <p><i>Chest al è test corsîf</i></p> + <p><u>Chest al è test sotlineât</u></p> + <p><center>Chest test al vignarà centrât.</center></p> + <p><s>Chest al è stricât</s></p> + + <p>Esempli di codiç: + <code>ls -l /home</code></p> + + <p><b>Listis:</b></p> + <ul> + <li>Sistemis a CPU Intel</li> + <li>Sistemis a CPU AMD</li> + </ul> + + <p>La sbare di scoriment verticâl si pues justâ, cumò la largjece e je metude a 10.</p> Back - + Indaûr @@ -3946,7 +3981,7 @@ Output: Pick your user name and credentials to login and perform admin tasks - + Sielç e dopre il to non utent e lis credenziâls par jentrâ e eseguî ativitâts di aministradôr @@ -3966,12 +4001,12 @@ Output: Login Name - + Non di acès If more than one person will use this computer, you can create multiple accounts after installation. - + Se chest computer al vignarà doprât di plui personis, tu puedis creâ plui account dopo vê completade la instalazion. @@ -3986,7 +4021,7 @@ Output: This name will be used if you make the computer visible to others on a network. - + Si doprarà chest non se tu rindis visibil a altris chest computer suntune rêt. @@ -4006,12 +4041,12 @@ Output: Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals. - + Inserìs la stesse password dôs voltis, in mût di evitâ erôrs di batidure. Une buine password e contignarà un miscliç di letaris, numars e puntuazions, e sarà lungje almancul vot caratars e si scugnarà cambiâle a intervai regolârs. Validate passwords quality - + Convalidâ la cualitât des passwords @@ -4021,12 +4056,12 @@ Output: Log in automatically without asking for the password - + Jentre in automatic cence domandâ la password Reuse user password as root password - + Torne dopre la password dal utent pe password di root @@ -4036,22 +4071,22 @@ Output: Choose a root password to keep your account safe. - + Sielç une password di root par tignî il to account al sigûr. Root Password - + Password di root Repeat Root Password - + Ripeti password di root Enter the same password twice, so that it can be checked for typing errors. - + Inserìs la stesse password dôs voltis, in mût di evitâ erôrs di batidure. @@ -4060,32 +4095,33 @@ Output: <h3>Welcome to the %1 <quote>%2</quote> installer</h3> <p>This program will ask you some questions and set up %1 on your computer.</p> - + <h3>Benvignûts sul program di instalazion <quote>%2</quote> par %1</h3> + <p>Chest program al fasarà cualchi domande e al configurarà %1 sul to computer.</p> About - + Informazions Support - + Supuart Known issues - + Problemis cognossûts Release notes - + Notis di publicazion Donate - + Done diff --git a/lang/calamares_he.ts b/lang/calamares_he.ts index 6c7ea88d8..5ed81a899 100644 --- a/lang/calamares_he.ts +++ b/lang/calamares_he.ts @@ -11,12 +11,12 @@ This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. - מערכת זו הופעלה בתצורת אתחול <strong>EFI</strong>.<br><br> כדי להגדיר הפעלה מתצורת אתחול EFI, על אשף ההתקנה להתקין מנהל אתחול מערכת, לדוגמה <strong>GRUB</strong> או <strong>systemd-boot</strong> על <strong>מחיצת מערכת EFI</strong>. פעולה זו היא אוטומטית, אלא אם כן העדפתך היא להגדיר מחיצות באופן ידני, במקרה זה עליך לבחור זאת או להגדיר בעצמך. + מערכת זו הופעלה בתצורת אתחול <strong>EFI</strong>.<br><br> כדי להגדיר הפעלה מתצורת אתחול EFI, על תכנית ההתקנה להתקין מנהל אתחול מערכת, לדוגמה <strong>GRUB</strong> או <strong>systemd-boot</strong> על <strong>מחיצת מערכת EFI</strong>. פעולה זו היא אוטומטית, אלא אם כן העדפתך היא להגדיר מחיצות באופן ידני, במקרה זה יש לבחור זאת או להגדיר בעצמך. This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. - מערכת זו הופעלה בתצורת אתחול <strong>BIOS</strong>.<br><br> כדי להגדיר הפעלה מתצורת אתחול BIOS, על אשף ההתקנה להתקין מנהל אתחול מערכת, לדוגמה <strong>GRUB</strong>, בתחילת המחיצה או על ה־<strong>Master Boot Record</strong> בצמוד להתחלה של טבלת המחיצות (מועדף). פעולה זו היא אוטומטית, אלא אם כן תבחר להגדיר מחיצות באופן ידני, במקרה זה עליך להגדיר זאת בעצמך. + מערכת זו הופעלה בתצורת אתחול <strong>BIOS</strong>.<br><br> כדי להגדיר הפעלה מתצורת אתחול BIOS, על תכנית ההתקנה להתקין מנהל אתחול מערכת, לדוגמה <strong>GRUB</strong>, בתחילת המחיצה או על ה־<strong>Master Boot Record</strong> בצמוד להתחלה של טבלת המחיצות (מועדף). פעולה זו היא אוטומטית, אלא אם כן תבחר להגדיר מחיצות באופן ידני, במקרה זה יש להגדיר זאת בעצמך. @@ -340,7 +340,7 @@ The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> - אשף ההתקנה של %1 הולך לבצע שינויים בכונן שלך לטובת התקנת %2.<br/><strong>לא תוכל לבטל את השינויים הללו.</strong> + תכנית ההתקנה של %1 עומדת לבצע שינויים בכונן שלך לטובת התקנת %2.<br/><strong>לא תהיה אפשרות לבטל את השינויים הללו.</strong> @@ -375,7 +375,7 @@ The installation is complete. Close the installer. - תהליך ההתקנה הושלם. נא לסגור את אשף ההתקנה. + תהליך ההתקנה הושלם. נא לסגור את תכנית ההתקנה. @@ -428,8 +428,8 @@ The setup program will quit and all changes will be lost. Do you really want to cancel the current install process? The installer will quit and all changes will be lost. - האם ברצונך לבטל את תהליך ההתקנה? -אשף ההתקנה ייסגר וכל השינויים יאבדו. + האם אכן ברצונך לבטל את תהליך ההתקנה? +תכנית ההתקנה תיסגר וכל השינויים יאבדו. @@ -437,7 +437,7 @@ The installer will quit and all changes will be lost. Unknown exception type - טיפוס חריגה אינו מוכר + סוג חריגה לא מוכר @@ -495,7 +495,7 @@ The installer will quit and all changes will be lost. %1 Installer - אשף התקנה של %1 + תכנית התקנת %1 @@ -638,7 +638,7 @@ The installer will quit and all changes will be lost. No Swap - בלי החלפה + ללא החלפה @@ -1117,7 +1117,7 @@ The installer will quit and all changes will be lost. The installer failed to delete partition %1. - אשף ההתקנה נכשל בעת מחיקת מחיצה %1. + תכנית ההתקנה כשלה במחיקת המחיצה %1. @@ -1644,7 +1644,7 @@ The installer will quit and all changes will be lost. If you do not agree with the terms, the setup procedure cannot continue. - אם התנאים האלה אינם מקובלים עליך, אי אפשר להמשיך בתהליך ההתקנה. + אם התנאים האלה אינם מקובלים עליכם, אי אפשר להמשיך בתהליך ההתקנה. @@ -1654,7 +1654,7 @@ The installer will quit and all changes will be lost. If you do not agree with the terms, proprietary software will not be installed, and open source alternatives will be used instead. - אם תנאים אלו אינם מקובלים עליך, לא תותקן תכנה קניינית וייעשה שימוש בחלופות בקוד פתוח במקום. + אם התנאים הללו אינם מקובלים עליכם, תוכנה קניינית לא תותקן, ובמקומן יעשה שימוש בחלופות בקוד פתוח. @@ -1826,8 +1826,8 @@ The installer will quit and all changes will be lost. Please select your preferred location on the map so the installer can suggest the locale and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming. - נא לבחור את המיקום המועדף עליך על המפה כדי שתכנית ההתקנה תוכל להציע הגדרות מקומיות - ואזור זמן עבורך. ניתן לכוונן את ההגדרות המוצעות להלן. לחפש במפה על ידי משיכה להזזתה ובכפתורים +/- כדי להתקרב/להתרחק + נא לבחור את המיקום המועדף עליכם על המפה כדי שתכנית ההתקנה תוכל להציע הגדרות מקומיות + ואזור זמן עבורכם. ניתן לכוונן את ההגדרות המוצעות להלן. לחפש במפה על ידי משיכה להזזתה ובכפתורים +/- כדי להתקרב/להתרחק או להשתמש בגלילת העכבר לטובת שליטה בתקריב. @@ -1974,7 +1974,7 @@ The installer will quit and all changes will be lost. Select your preferred Region, or use the default one based on your current location. - נא לבחור את המחוז המועדף עליך או להשתמש בבררת המחדל לפי המיקום הנוכחי שלך. + נא לבחור את המחוז המועדף עליכם או להשתמש בברירת המחדל לפי המיקום הנוכחי שלכם. @@ -2029,7 +2029,7 @@ The installer will quit and all changes will be lost. The password is the same as the old one - הססמה זהה לישנה + הססמה הזו זהה לישנה @@ -2413,7 +2413,7 @@ The installer will quit and all changes will be lost. <small>Enter the same password twice, so that it can be checked for typing errors.</small> - <small>עליך להקליד את אותה הססמה פעמיים כדי לאפשר זיהוי של שגיאות הקלדה.</small> + <small>יש להקליד את אותה הססמה פעמיים כדי לאפשר זיהוי של שגיאות הקלדה.</small> @@ -2648,12 +2648,12 @@ The installer will quit and all changes will be lost. An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a FAT32 filesystem with the <strong>%3</strong> flag enabled and mount point <strong>%2</strong>.<br/><br/>You can continue without setting up an EFI system partition but your system may fail to start. - מחיצת מערכת EFI נדרשת כדי להפעיל את %1.<br/><br/> כדי להגדיר מחיצת מערכת EFI, עליך לחזור ולבחור או ליצור מערכת קבצים מסוג FAT32 עם סימון <strong>%3</strong> פעיל ועם נקודת עיגון <strong>%2</strong>.<br/><br/> ניתן להמשיך ללא הגדרת מחיצת מערכת EFI אך טעינת המערכת עשויה להיכשל. + מחיצת מערכת EFI נדרשת כדי להפעיל את %1.<br/><br/> כדי להגדיר מחיצת מערכת EFI, יש לחזור ולבחור או ליצור מערכת קבצים מסוג FAT32 עם סימון <strong>%3</strong> פעיל ועם נקודת עיגון <strong>%2</strong>.<br/><br/> ניתן להמשיך ללא הגדרת מחיצת מערכת EFI אך טעינת המערכת עשויה להיכשל. An EFI system partition is necessary to start %1.<br/><br/>A partition was configured with mount point <strong>%2</strong> but its <strong>%3</strong> flag is not set.<br/>To set the flag, go back and edit the partition.<br/><br/>You can continue without setting the flag but your system may fail to start. - לצורך הפעלת %1 נדרשת מחיצת מערכת EFI.<br/><br/> הוגדרה מחיצה עם נקודת עיגון <strong>%2</strong> אך לא הוגדר סימון <strong>%3</strong>.<br/> כדי לסמן את המחיצה, עליך לחזור ולערוך את המחיצה.<br/><br/> ניתן להמשיך ללא הוספת הסימון אך טעינת המערכת עשויה להיכשל. + לצורך הפעלת %1 נדרשת מחיצת מערכת EFI.<br/><br/> הוגדרה מחיצה עם נקודת עיגון <strong>%2</strong> אך לא הוגדר סימון <strong>%3</strong>.<br/> כדי לסמן את המחיצה, יש לחזור ולערוך את המחיצה.<br/><br/> ניתן להמשיך ללא הוספת הסימון אך טעינת המערכת עשויה להיכשל. @@ -2843,7 +2843,7 @@ Output: swap - דפדוף, swap + דפדוף swap @@ -3886,7 +3886,7 @@ Output: Click your preferred keyboard model to select layout and variant, or use the default one based on the detected hardware. - נא ללחוץ על דרם המקלדת המועדף עליך כדי לבחור בפריסה ובהגוון או להשתמש בבררת המחדל בהתאם לחומרה שזוהתה. + נא ללחוץ על דגם המקלדת המועדף עליכם כדי לבחור בפריסה ובהגוון או להשתמש בברירת המחדל בהתאם לחומרה שזוהתה. diff --git a/lang/calamares_hi.ts b/lang/calamares_hi.ts index 1f220d9e5..f6d73519d 100644 --- a/lang/calamares_hi.ts +++ b/lang/calamares_hi.ts @@ -619,17 +619,17 @@ The installer will quit and all changes will be lost. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + इस संचय उपकरण पर पहले से ऑपरेटिंग सिस्टम है, परंतु <strong>%1</strong> विभाजन तालिका अपेक्षित <strong>%2</strong> से भिन्न है।<br/> This storage device has one of its partitions <strong>mounted</strong>. - + इस संचय उपकरण के विभाजनों में से कोई एक विभाजन <strong>माउंट</strong> है। This storage device is a part of an <strong>inactive RAID</strong> device. - + यह संचय उपकरण एक <strong>निष्क्रिय RAID</strong> उपकरण का हिस्सा है। diff --git a/lang/calamares_hr.ts b/lang/calamares_hr.ts index e9e5c252a..eae13403d 100644 --- a/lang/calamares_hr.ts +++ b/lang/calamares_hr.ts @@ -621,7 +621,7 @@ Instalacijski program će izaći i sve promjene će biti izgubljene. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Ovaj uređaj za pohranu već ima operativni sustav, ali njegova particijska tablica <strong>%1</strong> razlikuje se od potrebne <strong>%2</strong>.<br/> @@ -3067,12 +3067,12 @@ Postavljanje se može nastaviti, ali neke će značajke možda biti onemogućene The filesystem %1 could not be found in this system, and cannot be resized. - Datotečni sustav % 1 nije moguće pronaći na ovom sustavu i ne može mu se promijeniti veličina. + Datotečni sustav %1 nije moguće pronaći na ovom sustavu i ne može mu se promijeniti veličina. The device %1 could not be found in this system, and cannot be resized. - Uređaj % 1 nije moguće pronaći na ovom sustavu i ne može mu se promijeniti veličina. + Uređaj %1 nije moguće pronaći na ovom sustavu i ne može mu se promijeniti veličina. diff --git a/lang/calamares_hu.ts b/lang/calamares_hu.ts index f7651406c..e0ca6cd41 100644 --- a/lang/calamares_hu.ts +++ b/lang/calamares_hu.ts @@ -1620,7 +1620,7 @@ Telepítés nem folytatható. <a href="#details">Részletek...</a> <h1>License Agreement</h1> - + <h1>Licenszszerződés</h1> diff --git a/lang/calamares_ja.ts b/lang/calamares_ja.ts index 0a798b844..3a820770f 100644 --- a/lang/calamares_ja.ts +++ b/lang/calamares_ja.ts @@ -617,7 +617,7 @@ The installer will quit and all changes will be lost. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + このストレージデバイスにはすでにオペレーティングシステムがインストールされていますが、パーティションテーブル <strong>%1</strong> は必要な <strong>%2</strong> とは異なります。<br/> diff --git a/lang/calamares_ko.ts b/lang/calamares_ko.ts index 481637f00..3a5820569 100644 --- a/lang/calamares_ko.ts +++ b/lang/calamares_ko.ts @@ -304,12 +304,12 @@ Calamares Initialization Failed - Calamares 초기화 실패 + 깔라마레스 초기화 실패 %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. - %1 가 설치될 수 없습니다. Calamares가 모든 구성된 모듈을 불러올 수 없었습니다. 이것은 Calamares가 분포에 의해 사용되는 방식에서 비롯된 문제입니다. + %1 가 설치될 수 없습니다. 깔라마레스가 모든 구성된 모듈을 불러올 수 없었습니다. 이것은 깔라마레스가 배포판에서 사용되는 방식에서 발생한 문제입니다. @@ -617,17 +617,17 @@ The installer will quit and all changes will be lost. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + 이 스토리지 장치에는 이미 운영 체제가 설치되어 있으나 <strong>%1</strong> 파티션 테이블이 필요로 하는 <strong>%2</strong>와 다릅니다.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + 이 스토리지 장치는 하나 이상의 <strong>마운트된</strong> 파티션을 갖고 있습니다. This storage device is a part of an <strong>inactive RAID</strong> device. - + 이 스토리지 장치는 <strong>비활성화된 RAID</strong> 장치의 일부입니다. @@ -730,7 +730,7 @@ The installer will quit and all changes will be lost. Set timezone to %1/%2. - + 표준시간대를 %1/%2로 설정합니다. @@ -790,22 +790,22 @@ The installer will quit and all changes will be lost. <h1>Welcome to the Calamares setup program for %1</h1> - + <h1> 깔라마레스 설치 프로그램 %1에 오신 것을 환영합니다</h1> <h1>Welcome to %1 setup</h1> - + <h1>%1 설치에 오신 것을 환영합니다</h1> <h1>Welcome to the Calamares installer for %1</h1> - + <h1>깔라마레스 인스톨러 %1에 오신 것을 환영합니다</h1> <h1>Welcome to the %1 installer</h1> - + <h1>%1 인스톨러에 오신 것을 환영합니다</h1> @@ -815,7 +815,7 @@ The installer will quit and all changes will be lost. '%1' is not allowed as username. - + '%1'은 사용자 이름으로 허용되지 않습니다. @@ -840,7 +840,7 @@ The installer will quit and all changes will be lost. '%1' is not allowed as hostname. - + '%1'은 호스트 이름으로 허용되지 않습니다. @@ -1813,7 +1813,7 @@ The installer will quit and all changes will be lost. Timezone: %1 - + 표준시간대: %1 @@ -1945,7 +1945,7 @@ The installer will quit and all changes will be lost. <html><head/><body><h1>OEM Configuration</h1><p>Calamares will use OEM settings while configuring the target system.</p></body></html> - <html><head/><body><h1>OEM 구성</h1> <p>Calamares는 대상 시스템을 구성하는 동안 OEM 설정을 사용합니다.</p></body></html> + <html><head/><body><h1>OEM 구성</h1> <p>깔라마레스는 대상 시스템을 구성하는 동안 OEM 설정을 사용합니다.</p></body></html> @@ -1973,22 +1973,22 @@ The installer will quit and all changes will be lost. Timezone: %1 - + 표준시간대: %1 Select your preferred Zone within your Region. - + 선호하는 표준시간대와 지역을 선택하세요. Zones - + 표준시간대 You can fine-tune Language and Locale settings below. - + 아래에서 언어 및 로케일을 상세하게 설정할 수 있습니다. @@ -2864,7 +2864,7 @@ Output: Directory not found - + 디렉터리를 찾을 수 없습니다 @@ -3044,7 +3044,7 @@ Output: Calamares cannot start KPMCore for the file-system resize job. - Calamares는 파일 시스템 크기 조정 작업을 위해 KPMCore를 시작할 수 없습니다. + 깔라마레스는 파일 시스템 크기 조정 작업을 위해 KPMCore를 시작할 수 없습니다. @@ -3482,18 +3482,18 @@ Output: KDE user feedback - + KDE 사용자 의견 Configuring KDE user feedback. - + KDE 사용자 의견을 설정하는 중입니다. Error in KDE user feedback configuration. - + KDE 사용자 의견 설정 중에 오류가 발생했습니다. @@ -3744,7 +3744,7 @@ Output: <h1>Welcome to the Calamares setup program for %1.</h1> - <h1>%1에 대한 Calamares 설정 프로그램에 오신 것을 환영합니다.</h1> + <h1>%1에 대한 깔라마레스 설정 프로그램에 오신 것을 환영합니다.</h1> @@ -3754,7 +3754,7 @@ Output: <h1>Welcome to the Calamares installer for %1.</h1> - <h1>%1을 위한 Calamares 설치 관리자에 오신 것을 환영합니다.</h1> + <h1>%1을 위한 깔라마레스 설치 관리자에 오신 것을 환영합니다.</h1> @@ -3877,7 +3877,7 @@ Output: Keyboard Variant - + 키보드 유형 @@ -3890,7 +3890,7 @@ Output: Change - + 변경 @@ -3941,7 +3941,7 @@ Output: Pick your user name and credentials to login and perform admin tasks - + 로그인 및 관리자 작업을 수행하려면 사용자 이름과 자격 증명을 선택하세요 @@ -3961,7 +3961,7 @@ Output: Login Name - + 로그인 이름 @@ -4006,7 +4006,7 @@ Output: Validate passwords quality - + 패스워드 품질 검증 @@ -4016,12 +4016,12 @@ Output: Log in automatically without asking for the password - + 패스워드를 묻지 않고 자동으로 로그인합니다 Reuse user password as root password - + 사용자 패스워드를 루트 패스워드로 재사용합니다 @@ -4031,22 +4031,22 @@ Output: Choose a root password to keep your account safe. - + 당신의 계정을 안전하게 보호하기 위해서 루트 패스워드를 선택하세요. Root Password - + 루트 패스워드 Repeat Root Password - + 루트 패스워드 확인 Enter the same password twice, so that it can be checked for typing errors. - + 입력 오류를 확인하기 위해서 동일한 패스워드를 두번 입력해주세요. @@ -4060,7 +4060,7 @@ Output: About - Calamares에 대하여 + 깔라마레스에 대하여 diff --git a/lang/calamares_lt.ts b/lang/calamares_lt.ts index 676603ca3..0adb509ac 100644 --- a/lang/calamares_lt.ts +++ b/lang/calamares_lt.ts @@ -2870,7 +2870,7 @@ Išvestis: Directory not found - + Katalogas nerastas @@ -3885,7 +3885,7 @@ Išvestis: Keyboard Variant - + Klaviatūros variantas @@ -3989,7 +3989,7 @@ Išvestis: Login Name - + Prisijungimo vardas @@ -4009,7 +4009,7 @@ Išvestis: This name will be used if you make the computer visible to others on a network. - + Šis vardas bus naudojamas, jeigu padarysite savo kompiuterį matomą kitiems naudotojams tinkle. @@ -4074,7 +4074,7 @@ Išvestis: Enter the same password twice, so that it can be checked for typing errors. - + Norint įsitikinti, kad rašydami slaptažodį nesuklydote, įrašykite tą patį slaptažodį du kartus. diff --git a/lang/calamares_nl.ts b/lang/calamares_nl.ts index f9276e02e..370ddf890 100644 --- a/lang/calamares_nl.ts +++ b/lang/calamares_nl.ts @@ -3012,7 +3012,7 @@ Uitvoer: <p>This computer does not satisfy the minimum requirements for installing %1.<br/> Installation cannot continue.</p> - Deze computer voldoet niet aan de minimale vereisten voor het installeren van % 1. + Deze computer voldoet niet aan de minimale vereisten voor het installeren van %1. De installatie kan niet doorgaan. diff --git a/lang/calamares_pt_BR.ts b/lang/calamares_pt_BR.ts index 242303308..438a0a47e 100644 --- a/lang/calamares_pt_BR.ts +++ b/lang/calamares_pt_BR.ts @@ -619,17 +619,17 @@ O instalador será fechado e todas as alterações serão perdidas. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + O dispositivo de armazenamento já possui um sistema operacional, mas a tabela de partições <strong>%1</strong> é diferente da necessária <strong>%2</strong>.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + O dispositivo de armazenamento tem uma de suas partições <strong>montada</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + O dispositivo de armazenamento é parte de um dispositivo <strong>RAID inativo</strong>. @@ -2015,7 +2015,7 @@ O instalador será fechado e todas as alterações serão perdidas. Memory allocation error when setting '%1' - Erro de alocação de memória ao definir '% 1' + Erro de alocação de memória ao definir '%1' diff --git a/lang/calamares_sk.ts b/lang/calamares_sk.ts index eaef4dad4..6ddd9d534 100644 --- a/lang/calamares_sk.ts +++ b/lang/calamares_sk.ts @@ -623,17 +623,18 @@ Inštalátor sa ukončí a všetky zmeny budú stratené. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Toto úložné zariadenie už obsahuje operačný systém, ale tabuľka oddielov <strong>%1</strong> sa líši od požadovanej <strong>%2</strong>. +<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Toto úložné zariadenie má jeden zo svojich oddielov <strong>pripojený</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Toto úložné zariadenie je súčasťou zariadenia s <strong>neaktívnym RAIDom</strong>. @@ -1826,7 +1827,8 @@ Inštalátor sa ukončí a všetky zmeny budú stratené. Please select your preferred location on the map so the installer can suggest the locale and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming. - + Prosím, vyberte vaše preferované umiestnenie, aby mohol inštalátor pre vás navrhnúť + miestne nastavenia a časovú zónu. Navrhnuté nastavenia môžete doladiť nižšie. Mapu môžete presúvať ťahaním a približovať alebo odďaľovať tlačidlami +/- alebo rolovaním myšou. @@ -2127,7 +2129,7 @@ Inštalátor sa ukončí a všetky zmeny budú stratené. The password contains more than %1 same characters consecutively - Heslo obsahuje viac ako% 1 rovnakých znakov za sebou + Heslo obsahuje viac ako %1 rovnakých znakov za sebou @@ -2137,7 +2139,7 @@ Inštalátor sa ukončí a všetky zmeny budú stratené. The password contains more than %1 characters of the same class consecutively - Heslo obsahuje postupne viac ako% 1 znakov toho istého typu + Heslo obsahuje postupne viac ako %1 znakov toho istého typu @@ -2870,7 +2872,7 @@ Výstup: Directory not found - + Adresár sa nenašiel @@ -3873,7 +3875,7 @@ Výstup: Click your preferred keyboard model to select layout and variant, or use the default one based on the detected hardware. - + Kliknutím na preferovaný model klávesnice vyberiete rozloženie, alebo použite predvolený, ktorý bol vybraný podľa rozpoznaného hardvéru. @@ -4012,12 +4014,12 @@ Výstup: Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals. - + Zadajte rovnaké heslo dvakrát, aby sa predišlo preklepom. Dobré heslo by malo obsahovať mix písmen, čísel a diakritiky, malo by mať dĺžku aspoň osem znakov a malo by byť pravidelne menené. Validate passwords quality - + Overiť kvalitu hesiel @@ -4032,7 +4034,7 @@ Výstup: Reuse user password as root password - + Znovu použiť používateľské heslo ako heslo správcu diff --git a/lang/calamares_sv.ts b/lang/calamares_sv.ts index 3f03caf4e..ec72fefa9 100644 --- a/lang/calamares_sv.ts +++ b/lang/calamares_sv.ts @@ -618,17 +618,17 @@ Alla ändringar kommer att gå förlorade. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Denna lagringsenhet har redan ett operativsystem installerat på sig, men partitionstabellen <strong>%1</strong> skiljer sig från den som behövs <strong>%2</strong>.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Denna lagringsenhet har en av dess partitioner <strong>monterad</strong>. This storage device is a part of an <strong>inactive RAID</strong> device. - + Denna lagringsenhet är en del av en <strong>inaktiv RAID</strong>enhet. diff --git a/lang/calamares_te.ts b/lang/calamares_te.ts index 4786aafd0..3201f80b6 100644 --- a/lang/calamares_te.ts +++ b/lang/calamares_te.ts @@ -25,7 +25,7 @@ automatic ఉంటుంది, మీరు మాన్యువల్ వి Master Boot Record of %1 - % 1 యొక్క మాస్టర్ బూట్ రికార్డ్ + %1 యొక్క మాస్టర్ బూట్ రికార్డ్ @@ -134,7 +134,7 @@ automatic ఉంటుంది, మీరు మాన్యువల్ వి Job failed (%1) - జాబ్ విఫలమైంది (% 1) + జాబ్ విఫలమైంది (%1) diff --git a/lang/calamares_tg.ts b/lang/calamares_tg.ts index eac2d747e..9c2910547 100644 --- a/lang/calamares_tg.ts +++ b/lang/calamares_tg.ts @@ -620,17 +620,17 @@ The installer will quit and all changes will be lost. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + Ин дастгоҳи захирагоҳ аллакай дорои низоми амалкунанда мебошад, аммо ҷадвали қисми диски <strong>%1</strong> аз диски лозимии <strong>%2</strong> фарқ мекунад.<br/> This storage device has one of its partitions <strong>mounted</strong>. - + Яке аз қисмҳои диски ин дастгоҳи захирагоҳ <strong>васлшуда</strong> мебошад. This storage device is a part of an <strong>inactive RAID</strong> device. - + Ин дастгоҳи захирагоҳ қисми дасгоҳи <strong>RAID-и ғайрифаъол</strong> мебошад. diff --git a/lang/calamares_vi.ts b/lang/calamares_vi.ts new file mode 100644 index 000000000..140da8aad --- /dev/null +++ b/lang/calamares_vi.ts @@ -0,0 +1,4124 @@ + + + + + BootInfoWidget + + + The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. + <strong> Môi trường khởi động </strong> của hệ thống này. <br> <br> Các hệ thống x86 cũ hơn chỉ hỗ trợ <strong> BIOS </strong>. <br> Các hệ thống hiện đại thường sử dụng <strong> EFI </strong>, nhưng cũng có thể hiển thị dưới dạng BIOS nếu được khởi động ở chế độ tương thích. + + + + This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. + Hệ thống này được khởi động bằng môi trường khởi động <strong> EFI </strong>. <br> <br> Để định cấu hình khởi động từ môi trường EFI, trình cài đặt này phải triển khai ứng dụng trình tải khởi động, như <strong> GRUB </strong> hoặc <strong> systemd-boot </strong> trên <strong> Phân vùng hệ thống EFI </strong>. Điều này là tự động, trừ khi bạn chọn phân vùng thủ công, trong trường hợp này, bạn phải chọn nó hoặc tự tạo nó. + + + + This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. + Hệ thống này được khởi động với môi trường khởi động <strong> BIOS </strong>. <br> <br> Để định cấu hình khởi động từ môi trường BIOS, trình cài đặt này phải cài đặt một trình tải khởi động, chẳng hạn như <strong> GRUB </strong> ở đầu phân vùng hoặc trên <strong> Bản ghi khởi động chính </strong> gần đầu bảng phân vùng (ưu tiên). Điều này là tự động, trừ khi bạn chọn phân vùng thủ công, trong trường hợp đó, bạn phải tự thiết lập nó. + + + + BootLoaderModel + + + Master Boot Record of %1 + Bản ghi khởi động chính của %1 + + + + Boot Partition + Phân vùng khởi động + + + + System Partition + Phân vùng hệ thống + + + + Do not install a boot loader + Không cài đặt bộ tải khởi động + + + + %1 (%2) + %1 (%2) + + + + Calamares::BlankViewStep + + + Blank Page + Trang trắng + + + + Calamares::DebugWindow + + + Form + Mẫu + + + + GlobalStorage + Lưu trữ tổng quát + + + + JobQueue + Hàng đợi công việc + + + + Modules + Mô-đun + + + + Type: + Kiểu: + + + + + none + không + + + + Interface: + Giao diện: + + + + Tools + Công cụ + + + + Reload Stylesheet + Tải lại bảng định kiểu + + + + Widget Tree + Cây công cụ + + + + Debug information + Thông tin gỡ lỗi + + + + Calamares::ExecutionViewStep + + + Set up + Thiết lập + + + + Install + Cài đặt + + + + Calamares::FailJob + + + Job failed (%1) + Công việc thất bại (%1) + + + + Programmed job failure was explicitly requested. + Lỗi công việc được lập trình đã được yêu cầu rõ ràng. + + + + Calamares::JobThread + + + Done + Xong + + + + Calamares::NamedJob + + + Example job (%1) + Ví dụ về công việc (%1) + + + + Calamares::ProcessJob + + + Run command '%1' in target system. + Chạy lệnh '%1' trong hệ thống đích. + + + + Run command '%1'. + Chạy lệnh '%1'. + + + + Running command %1 %2 + Đang chạy lệnh %1 %2 + + + + Calamares::PythonJob + + + Running %1 operation. + Đang chạy %1 thao tác. + + + + Bad working directory path + Sai đường dẫn thư mục làm việc + + + + Working directory %1 for python job %2 is not readable. + Không thể đọc thư mục làm việc %1 của công việc python %2. + + + + Bad main script file + Sai tệp kịch bản chính + + + + Main script file %1 for python job %2 is not readable. + Không thể đọc tập tin kịch bản chính %1 của công việc python %2. + + + + Boost.Python error in job "%1". + Lỗi Boost.Python trong công việc "%1". + + + + Calamares::QmlViewStep + + + Loading ... + Đang tải ... + + + + QML Step <i>%1</i>. + QML bước <i>%1</i>. + + + + Loading failed. + Không tải được. + + + + Calamares::RequirementsChecker + + + Requirements checking for module <i>%1</i> is complete. + Kiểm tra các yêu cầu cho mô-đun <i> %1 </i> đã hoàn tất. + + + + Waiting for %n module(s). + + Đang đợi %n mô-đun. + + + + + (%n second(s)) + + (%n giây) + + + + + System-requirements checking is complete. + Kiểm tra yêu cầu hệ thống đã hoàn tất. + + + + Calamares::ViewManager + + + Setup Failed + Thiết lập không thành công + + + + Installation Failed + Cài đặt thất bại + + + + Would you like to paste the install log to the web? + Bạn có muốn gửi nhật ký cài đặt lên web không? + + + + Error + Lỗi + + + + + &Yes + &Có + + + + + &No + &Không + + + + &Close + Đón&g + + + + Install Log Paste URL + URL để gửi nhật ký cài đặt + + + + The upload was unsuccessful. No web-paste was done. + Tải lên không thành công. Không có quá trình gửi lên web nào được thực hiện. + + + + Calamares Initialization Failed + Khởi tạo không thành công + + + + %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. + %1 không thể được cài đặt.Không thể tải tất cả các mô-đun đã định cấu hình. Đây là vấn đề với cách phân phối sử dụng. + + + + <br/>The following modules could not be loaded: + <br/> Không thể tải các mô-đun sau: + + + + Continue with setup? + Tiếp tục thiết lập? + + + + Continue with installation? + Tiếp tục cài đặt? + + + + The %1 setup program is about to make changes to your disk in order to set up %2.<br/><strong>You will not be able to undo these changes.</strong> + Chương trình thiết lập %1 sắp thực hiện các thay đổi đối với đĩa của bạn để thiết lập %2. <br/> <strong> Bạn sẽ không thể hoàn tác các thay đổi này. </strong> + + + + The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> + Trình cài đặt %1 sắp thực hiện các thay đổi đối với đĩa của bạn để cài đặt %2. <br/> <strong> Bạn sẽ không thể hoàn tác các thay đổi này. </strong> + + + + &Set up now + &Thiết lập ngay + + + + &Install now + &Cài đặt ngay + + + + Go &back + &Quay lại + + + + &Set up + &Thiết lập + + + + &Install + &Cài đặt + + + + Setup is complete. Close the setup program. + Thiết lập hoàn tất. Đóng chương trình cài đặt. + + + + The installation is complete. Close the installer. + Quá trình cài đặt hoàn tất. Đóng trình cài đặt. + + + + Cancel setup without changing the system. + Hủy thiết lập mà không thay đổi hệ thống. + + + + Cancel installation without changing the system. + Hủy cài đặt mà không thay đổi hệ thống. + + + + &Next + &Tiếp + + + + &Back + &Quay lại + + + + &Done + &Xong + + + + &Cancel + &Hủy + + + + Cancel setup? + Hủy thiết lập? + + + + Cancel installation? + Hủy cài đặt? + + + + Do you really want to cancel the current setup process? +The setup program will quit and all changes will be lost. + Bạn có thực sự muốn hủy quá trình thiết lập hiện tại không? +Chương trình thiết lập sẽ thoát và tất cả các thay đổi sẽ bị mất. + + + + Do you really want to cancel the current install process? +The installer will quit and all changes will be lost. + Bạn có thực sự muốn hủy quá trình cài đặt hiện tại không? +Trình cài đặt sẽ thoát và tất cả các thay đổi sẽ bị mất. + + + + CalamaresPython::Helper + + + Unknown exception type + Không nhận ra kiểu của ngoại lệ + + + + unparseable Python error + lỗi không thể phân tích cú pháp Python + + + + unparseable Python traceback + truy vết không thể phân tích cú pháp Python + + + + Unfetchable Python error. + Lỗi Python không thể try cập. + + + + CalamaresUtils + + + Install log posted to: +%1 + Cài đặt nhật ký được đăng lên: +%1 + + + + CalamaresWindow + + + Show debug information + Hiện thông tin gỡ lỗi + + + + &Back + Trở &về + + + + &Next + &Tiếp theo + + + + &Cancel + &Hủy bỏ + + + + %1 Setup Program + %1 Thiết lập chương trình + + + + %1 Installer + %1 cài đặt hệ điều hành + + + + CheckerContainer + + + Gathering system information... + Thu thập thông tin hệ thống ... + + + + ChoicePage + + + Form + Biểu mẫu + + + + Select storage de&vice: + &Chọn thiết bị lưu trữ: + + + + + + + Current: + Hiện tại: + + + + After: + Sau khi cài đặt: + + + + <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. + <strong> Phân vùng thủ công </strong> <br/> Bạn có thể tự tạo hoặc thay đổi kích thước phân vùng. + + + + Reuse %1 as home partition for %2. + Sử dụng lại %1 làm phân vùng chính cho %2. + + + + <strong>Select a partition to shrink, then drag the bottom bar to resize</strong> + <strong> Chọn một phân vùng để thu nhỏ, sau đó kéo thanh dưới cùng để thay đổi kích thước </strong> + + + + %1 will be shrunk to %2MiB and a new %3MiB partition will be created for %4. + %1 sẽ được thu nhỏ thành %2MiB và phân vùng %3MiB mới sẽ được tạo cho %4. + + + + Boot loader location: + Vị trí bộ tải khởi động: + + + + <strong>Select a partition to install on</strong> + <strong> Chọn phân vùng để cài đặt </strong> + + + + An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. + Không thể tìm thấy phân vùng hệ thống EFI ở bất kỳ đâu trên hệ thống này. Vui lòng quay lại và sử dụng phân vùng thủ công để thiết lập %1. + + + + The EFI system partition at %1 will be used for starting %2. + Phân vùng hệ thống EFI tại %1 sẽ được sử dụng để bắt đầu %2. + + + + EFI system partition: + Phân vùng hệ thống EFI: + + + + This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + Thiết bị lưu trữ này dường như không có hệ điều hành trên đó. Bạn muốn làm gì? <br/> Bạn sẽ có thể xem xét và xác nhận lựa chọn của mình trước khi thực hiện bất kỳ thay đổi nào đối với thiết bị lưu trữ. + + + + + + + <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. + <strong> Xóa đĩa </strong> <br/> Thao tác này sẽ <font color = "red"> xóa </font> tất cả dữ liệu hiện có trên thiết bị lưu trữ đã chọn. + + + + + + + <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. + <strong> Cài đặt cùng với </strong> <br/> Trình cài đặt sẽ thu nhỏ phân vùng để nhường chỗ cho %1. + + + + + + + <strong>Replace a partition</strong><br/>Replaces a partition with %1. + <strong> Thay thế phân vùng </strong> <br/> Thay thế phân vùng bằng %1. + + + + This storage device has %1 on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + Thiết bị lưu trữ này có %1 trên đó. Bạn muốn làm gì? <br/> Bạn sẽ có thể xem lại và xác nhận lựa chọn của mình trước khi thực hiện bất kỳ thay đổi nào đối với thiết bị lưu trữ. + + + + This storage device already has an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + Thiết bị lưu trữ này đã có hệ điều hành trên đó. Bạn muốn làm gì? <br/> Bạn sẽ có thể xem lại và xác nhận lựa chọn của mình trước khi thực hiện bất kỳ thay đổi nào đối với thiết bị lưu trữ. + + + + This storage device has multiple operating systems on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + Thiết bị lưu trữ này có nhiều hệ điều hành trên đó. Bạn muốn làm gì? <br/> Bạn sẽ có thể xem lại và xác nhận lựa chọn của mình trước khi thực hiện bất kỳ thay đổi nào đối với thiết bị lưu trữ. + + + + This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> + Thiết bị lưu trữ này đã có sẵn hệ điều hành, nhưng bảng phân vùng <strong> %1 </strong> khác với bảng <strong> %2 </strong> cần thiết. <br/> + + + + This storage device has one of its partitions <strong>mounted</strong>. + Thiết bị lưu trữ này có một trong các phân vùng được <strong> gắn kết </strong>. + + + + This storage device is a part of an <strong>inactive RAID</strong> device. + Thiết bị lưu trữ này là một phần của thiết bị <strong> RAID không hoạt động </strong>. + + + + No Swap + Không hoán đổi + + + + Reuse Swap + Sử dụng lại Hoán đổi + + + + Swap (no Hibernate) + Hoán đổi (không ngủ đông) + + + + Swap (with Hibernate) + Hoán đổi (ngủ đông) + + + + Swap to file + Hoán đổi sang tệp + + + + ClearMountsJob + + + Clear mounts for partitioning operations on %1 + Xóa gắn kết cho các hoạt động phân vùng trên %1 + + + + Clearing mounts for partitioning operations on %1. + Xóa các gắn kết cho các hoạt động phân vùng trên %1. + + + + Cleared all mounts for %1 + Đã xóa tất cả các gắn kết cho %1 + + + + ClearTempMountsJob + + + Clear all temporary mounts. + Xóa tất cả các gắn kết tạm thời. + + + + Clearing all temporary mounts. + Đang xóa tất cả các gắn kết tạm thời. + + + + Cannot get list of temporary mounts. + Không thể lấy danh sách các gắn kết tạm thời. + + + + Cleared all temporary mounts. + Xóa tất cả các gắn kết tạm thời. + + + + CommandList + + + + Could not run command. + Không thể chạy lệnh. + + + + The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined. + Lệnh chạy trong môi trường máy chủ và cần biết đường dẫn gốc, nhưng không có biến rootMountPoint nào được xác định. + + + + The command needs to know the user's name, but no username is defined. + Lệnh cần biết tên của người dùng, nhưng không có tên người dùng nào được xác định. + + + + Config + + + Set keyboard model to %1.<br/> + Thiệt lập bàn phím kiểu %1.<br/> + + + + Set keyboard layout to %1/%2. + Thiết lập bố cục bàn phím thành %1/%2. + + + + Set timezone to %1/%2. + Thiết lập múi giờ sang %1/%2. + + + + The system language will be set to %1. + Ngôn ngữ hệ thống sẽ được đặt thành %1. + + + + The numbers and dates locale will be set to %1. + Định dạng ngôn ngữ của số và ngày tháng sẽ được chuyển thành %1. + + + + Network Installation. (Disabled: Incorrect configuration) + Cài đặt mạng. (Tắt: Sai cấu hình) + + + + Network Installation. (Disabled: Received invalid groups data) + Cài đặt mạng. (Tắt: Nhận được dữ liệu nhóm bị sai) + + + + Network Installation. (Disabled: internal error) + Cài đặt mạng. (Tắt: Lỗi nội bộ) + + + + Network Installation. (Disabled: Unable to fetch package lists, check your network connection) + Cài đặt mạng. (Tắt: Không thể lấy được danh sách gói ứng dụng, kiểm tra kết nối mạng) + + + + This computer does not satisfy the minimum requirements for setting up %1.<br/>Setup cannot continue. <a href="#details">Details...</a> + Máy tính này không đạt đủ yêu cấu tối thiểu để thiết lập %1.<br/>Không thể tiếp tục thiết lập. <a href="#details">Chi tiết...</a> + + + + This computer does not satisfy the minimum requirements for installing %1.<br/>Installation cannot continue. <a href="#details">Details...</a> + Máy tính này không đạt đủ yêu cấu tối thiểu để cài đặt %1.<br/>Không thể tiếp tục cài đặt. <a href="#details">Chi tiết...</a> + + + + This computer does not satisfy some of the recommended requirements for setting up %1.<br/>Setup can continue, but some features might be disabled. + Máy tính này không đạt đủ yêu cấu khuyến nghị để thiết lập %1.<br/>Thiết lập có thể tiếp tục, nhưng một số tính năng có thể sẽ bị tắt. + + + + This computer does not satisfy some of the recommended requirements for installing %1.<br/>Installation can continue, but some features might be disabled. + Máy tính này không đạt đủ yêu cấu khuyến nghị để cài đặt %1.<br/>Cài đặt có thể tiếp tục, nhưng một số tính năng có thể sẽ bị tắt. + + + + This program will ask you some questions and set up %2 on your computer. + Chương trình này sẽ hỏi bạn vài câu hỏi và thiết lập %2 trên máy tính của bạn. + + + + <h1>Welcome to the Calamares setup program for %1</h1> + <h1>Chào mừng đến với chương trình Calamares để thiết lập %1</h1> + + + + <h1>Welcome to %1 setup</h1> + <h1>Chào mừng đến với thiết lập %1 </h1> + + + + <h1>Welcome to the Calamares installer for %1</h1> + <h1>Chào mừng đến với chương trình Calamares để cài đặt %1</h1> + + + + <h1>Welcome to the %1 installer</h1> + <h1>Chào mừng đến với bộ cài đặt %1 </h1> + + + + Your username is too long. + Tên bạn hơi dài. + + + + '%1' is not allowed as username. + '%1' không được phép dùng làm tên. + + + + Your username must start with a lowercase letter or underscore. + Tên người dùng của bạn phải bắt đầu bằng chữ cái viết thường hoặc dấu gạch dưới. + + + + Only lowercase letters, numbers, underscore and hyphen are allowed. + Chỉ cho phép các chữ cái viết thường, số, gạch dưới và gạch nối. + + + + Your hostname is too short. + Tên máy chủ quá ngắn. + + + + Your hostname is too long. + Tên máy chủ quá dài. + + + + '%1' is not allowed as hostname. + '%1' không được phép dùng làm tên máy chủ. + + + + Only letters, numbers, underscore and hyphen are allowed. + Chỉ cho phép các chữ cái, số, gạch dưới và gạch nối. + + + + Your passwords do not match! + Mật khẩu nhập lại không khớp! + + + + ContextualProcessJob + + + Contextual Processes Job + Công việc xử lý theo ngữ cảnh + + + + CreatePartitionDialog + + + Create a Partition + Tạo phân vùng + + + + Si&ze: + &Kích thước: + + + + MiB + MiB + + + + Partition &Type: + &Loại phân vùng: + + + + &Primary + &Sơ cấp + + + + E&xtended + &Mở rộng + + + + Fi&le System: + &Tập tin hệ thống: + + + + LVM LV name + Tên LVM LV + + + + &Mount Point: + &Điểm gắn kết: + + + + Flags: + Cờ: + + + + En&crypt + &Mã hóa + + + + Logical + Lô-gic + + + + Primary + Sơ cấp + + + + GPT + GPT + + + + Mountpoint already in use. Please select another one. + Điểm gắn kết đã được sử dụng. Vui lòng chọn một cái khác. + + + + CreatePartitionJob + + + Create new %2MiB partition on %4 (%3) with file system %1. + Tạo phân vùng %2MiB mới trên %4 (%3) với hệ thống tệp %1. + + + + Create new <strong>%2MiB</strong> partition on <strong>%4</strong> (%3) with file system <strong>%1</strong>. + Tạo phân vùng <strong>%2MiB </strong> mới trên <strong>%4 </strong> (%3) với hệ thống tệp <strong>%1 </strong>. + + + + Creating new %1 partition on %2. + Tạo phân vùng %1 mới trên %2. + + + + The installer failed to create partition on disk '%1'. + Trình cài đặt không tạo được phân vùng trên đĩa '%1'. + + + + CreatePartitionTableDialog + + + Create Partition Table + Tạo bảng phân vùng + + + + Creating a new partition table will delete all existing data on the disk. + Tạo bảng phân vùng mới sẽ xóa tất cả dữ liệu hiện có trên đĩa. + + + + What kind of partition table do you want to create? + Bạn muốn tạo loại bảng phân vùng nào? + + + + Master Boot Record (MBR) + Bản ghi khởi động chính (MBR) + + + + GUID Partition Table (GPT) + Bảng phân vùng GUID (GPT) + + + + CreatePartitionTableJob + + + Create new %1 partition table on %2. + Tạo bảng phân vùng %1 mới trên %2. + + + + Create new <strong>%1</strong> partition table on <strong>%2</strong> (%3). + Tạo bảng phân vùng <strong>%1 </strong> mới trên <strong>%2 </strong> (%3). + + + + Creating new %1 partition table on %2. + Tạo bảng phân vùng %1 mới trên %2. + + + + The installer failed to create a partition table on %1. + Trình cài đặt không tạo được bảng phân vùng trên %1. + + + + CreateUserJob + + + Create user %1 + Khởi tạo người dùng %1 + + + + Create user <strong>%1</strong>. + Tạo người dùng <strong>%1</strong>. + + + + Creating user %1. + Đang tạo người dùng %1. + + + + Cannot create sudoers file for writing. + Không thể tạo tệp sudoers để viết. + + + + Cannot chmod sudoers file. + Không thể sửa đổi mod của tệp sudoers. + + + + CreateVolumeGroupDialog + + + Create Volume Group + Tạo nhóm ổ đĩa + + + + CreateVolumeGroupJob + + + Create new volume group named %1. + Tạo nhóm ổ đĩa mới có tên %1. + + + + Create new volume group named <strong>%1</strong>. + Tạo nhóm ổ đĩa mới có tên <strong>%1</strong>. + + + + Creating new volume group named %1. + Đang tạo nhóm ổ đĩa mới có tên %1. + + + + The installer failed to create a volume group named '%1'. + Trình cài đặt không tạo được nhóm ổ đĩa có tên '%1'. + + + + DeactivateVolumeGroupJob + + + + Deactivate volume group named %1. + Hủy kích hoạt nhóm ổ đĩa có tên %1. + + + + Deactivate volume group named <strong>%1</strong>. + Hủy kích hoạt nhóm ổ đĩa có tên <strong>%1</strong>. + + + + The installer failed to deactivate a volume group named %1. + Trình cài đặt không thể hủy kích hoạt nhóm ổ đĩa có tên %1. + + + + DeletePartitionJob + + + Delete partition %1. + Xóa phân vùng %1. + + + + Delete partition <strong>%1</strong>. + Xóa phân vùng <strong>%1</strong>. + + + + Deleting partition %1. + Đang xóa phân vùng %1. + + + + The installer failed to delete partition %1. + Trình cài đặt không thể xóa phân vùng %1. + + + + DeviceInfoWidget + + + This device has a <strong>%1</strong> partition table. + Thiết bị này có bảng phân vùng <strong> %1 </strong>. + + + + This is a <strong>loop</strong> device.<br><br>It is a pseudo-device with no partition table that makes a file accessible as a block device. This kind of setup usually only contains a single filesystem. + Đây là thiết bị <strong> vòng lặp </strong>. <br> <br> Đây là thiết bị giả không có bảng phân vùng giúp tệp có thể truy cập được dưới dạng thiết bị khối. Loại thiết lập này thường chỉ chứa một hệ thống tệp duy nhất. + + + + This installer <strong>cannot detect a partition table</strong> on the selected storage device.<br><br>The device either has no partition table, or the partition table is corrupted or of an unknown type.<br>This installer can create a new partition table for you, either automatically, or through the manual partitioning page. + Trình cài đặt này <strong> không thể phát hiện bảng phân vùng </strong> trên thiết bị lưu trữ đã chọn. <br> <br> Thiết bị không có bảng phân vùng hoặc bảng phân vùng bị hỏng hoặc thuộc loại không xác định. <br> Điều này trình cài đặt có thể tạo bảng phân vùng mới cho bạn, tự động hoặc thông qua trang phân vùng thủ công. + + + + <br><br>This is the recommended partition table type for modern systems which start from an <strong>EFI</strong> boot environment. + <br> <br> Đây là loại bảng phân vùng được khuyến nghị cho các hệ thống hiện đại bắt đầu từ môi trường khởi động <strong> EFI </strong>. + + + + <br><br>This partition table type is only advisable on older systems which start from a <strong>BIOS</strong> boot environment. GPT is recommended in most other cases.<br><br><strong>Warning:</strong> the MBR partition table is an obsolete MS-DOS era standard.<br>Only 4 <em>primary</em> partitions may be created, and of those 4, one can be an <em>extended</em> partition, which may in turn contain many <em>logical</em> partitions. + <br> <br> Loại bảng phân vùng này chỉ được khuyến khích trên các hệ thống cũ hơn bắt đầu từ môi trường khởi động <strong> BIOS </strong>. GPT được khuyến nghị trong hầu hết các trường hợp khác. <br> <br> <strong> Cảnh báo: </strong> bảng phân vùng MBR là tiêu chuẩn thời đại MS-DOS lỗi thời. <br> Chỉ có 4 phân vùng <em> chính </em> có thể được tạo và trong số 4 phân vùng đó, một phân vùng có thể là phân vùng <em> mở rộng </em>, đến lượt nó có thể chứa nhiều phân vùng <em> logic </em>. + + + + The type of <strong>partition table</strong> on the selected storage device.<br><br>The only way to change the partition table type is to erase and recreate the partition table from scratch, which destroys all data on the storage device.<br>This installer will keep the current partition table unless you explicitly choose otherwise.<br>If unsure, on modern systems GPT is preferred. + Loại <strong> bảng phân vùng </strong> trên thiết bị lưu trữ đã chọn. <br> <br> Cách duy nhất để thay đổi loại bảng phân vùng là xóa và tạo lại bảng phân vùng từ đầu, việc này sẽ hủy tất cả dữ liệu trên thiết bị lưu trữ. <br> Trình cài đặt này sẽ giữ bảng phân vùng hiện tại trừ khi bạn chọn rõ ràng khác. <br> Nếu không chắc chắn, trên các hệ thống hiện đại, GPT được ưu tiên hơn. + + + + DeviceModel + + + %1 - %2 (%3) + device[name] - size[number] (device-node[name]) + %1 - %2 (%3) + + + + %1 - (%2) + device[name] - (device-node[name]) + %1 - (%2) + + + + DracutLuksCfgJob + + + Write LUKS configuration for Dracut to %1 + Lưu cấu hình LUKS cho Dracut vào %1 + + + + Skip writing LUKS configuration for Dracut: "/" partition is not encrypted + Không lưu cấu hình LUKS cho Dracut: phân vùng "/" không được mã hoá + + + + Failed to open %1 + Mở %1 thất bại + + + + DummyCppJob + + + Dummy C++ Job + Công việc C++ ví dụ + + + + EditExistingPartitionDialog + + + Edit Existing Partition + Chỉnh sửa phân vùng hiện có + + + + Content: + Nội dung: + + + + &Keep + &Giữ + + + + Format + Định dạng + + + + Warning: Formatting the partition will erase all existing data. + Cảnh báo: Định dạng phân vùng sẽ xóa tất cả dữ liệu hiện có. + + + + &Mount Point: + &Điểm gắn kết: + + + + Si&ze: + &Kích thước: + + + + MiB + MiB + + + + Fi&le System: + &Tập tin hệ thống: + + + + Flags: + Cờ: + + + + Mountpoint already in use. Please select another one. + Điểm gắn kết đã được sử dụng. Vui lòng chọn một cái khác. + + + + EncryptWidget + + + Form + Biểu mẫu + + + + En&crypt system + &Mã hóa hệ thống + + + + Passphrase + Cụm mật khẩu + + + + Confirm passphrase + Xác nhận cụm mật khẩu + + + + + Please enter the same passphrase in both boxes. + Vui lòng nhập cùng một cụm mật khẩu vào cả hai hộp. + + + + FillGlobalStorageJob + + + Set partition information + Đặt thông tin phân vùng + + + + Install %1 on <strong>new</strong> %2 system partition. + Cài đặt %1 trên phân vùng hệ thống <strong> mới </strong> %2. + + + + Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong>. + Thiết lập phân vùng <strong> mới </strong> %2 với điểm gắn kết <strong> %1 </strong>. + + + + Install %2 on %3 system partition <strong>%1</strong>. + Cài đặt %2 trên phân vùng hệ thống %3 <strong> %1 </strong>. + + + + Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong>. + Thiết lập phân vùng %3 <strong> %1 </strong> với điểm gắn kết <strong> %2 </strong>. + + + + Install boot loader on <strong>%1</strong>. + Cài đặt trình tải khởi động trên <strong> %1 </strong>. + + + + Setting up mount points. + Thiết lập điểm gắn kết. + + + + FinishedPage + + + Form + Biểu mẫu + + + + &Restart now + &Khởi động lại ngay + + + + <h1>All done.</h1><br/>%1 has been set up on your computer.<br/>You may now start using your new system. + <h1>Hoàn thành.</h1><br/>%1 đã được cài đặt thành công.<br/>Hãy khởi động lại máy tính. + + + + <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style="font-style:italic;">Done</span> or close the setup program.</p></body></html> + <html><head/><body><p>Tích chọn để khởi động lại sau khi ấn <span style="font-style:italic;">Hoàn thành</span> hoặc đóng phần mềm thiết lập.</p></body></html> + + + + <h1>All done.</h1><br/>%1 has been installed on your computer.<br/>You may now restart into your new system, or continue using the %2 Live environment. + <h1>Hoàn thành.</h1><br/>%1 đã được cài đặt trên máy.<br/>hãy khởi động lại, hoặc cũng có thể tiếp tục sử dụng %2 môi trường USB. + + + + <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style="font-style:italic;">Done</span> or close the installer.</p></body></html> + <html><head/><body><p>Tích chọn để khởi động lại sau khi ấn <span style="font-style:italic;">Hoàn thành</span> hoặc đóng phần mềm cài đặt.</p></body></html> + + + + <h1>Setup Failed</h1><br/>%1 has not been set up on your computer.<br/>The error message was: %2. + <h1>Thiết lập lỗi</h1><br/>%1 đã không được thiết lập trên máy tính.<br/>tin báo lỗi: %2. + + + + <h1>Installation Failed</h1><br/>%1 has not been installed on your computer.<br/>The error message was: %2. + <h1>Cài đặt lỗi</h1><br/>%1 chưa được cài đặt trên máy tính<br/>Tin báo lỗi: %2. + + + + FinishedViewStep + + + Finish + Hoàn thành + + + + Setup Complete + Thiết lập xong + + + + Installation Complete + Cài đặt xong + + + + The setup of %1 is complete. + Thiết lập %1 đã xong. + + + + The installation of %1 is complete. + Cài đặt của %1 đã xong. + + + + FormatPartitionJob + + + Format partition %1 (file system: %2, size: %3 MiB) on %4. + Định dạng phân vùng %1 (tập tin hệ thống:%2, kích thước: %3 MiB) trên %4. + + + + Format <strong>%3MiB</strong> partition <strong>%1</strong> with file system <strong>%2</strong>. + Định dạng <strong>%3MiB</strong> phân vùng <strong>%1</strong>với tập tin hệ thống <strong>%2</strong>. + + + + Formatting partition %1 with file system %2. + Đang định dạng phân vùng %1 với tập tin hệ thống %2. + + + + The installer failed to format partition %1 on disk '%2'. + Không thể định dạng %1 ở đĩa '%2'. + + + + GeneralRequirements + + + has at least %1 GiB available drive space + có ít nhất %1 GiB dung lượng ổ đĩa khả dụng + + + + There is not enough drive space. At least %1 GiB is required. + Không có đủ dung lượng ổ đĩa. Ít nhất %1 GiB là bắt buộc. + + + + has at least %1 GiB working memory + có ít nhất %1 GiB bộ nhớ làm việc + + + + The system does not have enough working memory. At least %1 GiB is required. + Hệ thống không có đủ bộ nhớ hoạt động. Ít nhất %1 GiB là bắt buộc. + + + + is plugged in to a power source + được cắm vào nguồn điện + + + + The system is not plugged in to a power source. + Hệ thống chưa được cắm vào nguồn điện. + + + + is connected to the Internet + được kết nối với Internet + + + + The system is not connected to the Internet. + Hệ thống không được kết nối với Internet. + + + + is running the installer as an administrator (root) + đang chạy trình cài đặt với tư cách quản trị viên (root) + + + + The setup program is not running with administrator rights. + Chương trình thiết lập không chạy với quyền quản trị viên. + + + + The installer is not running with administrator rights. + Trình cài đặt không chạy với quyền quản trị viên. + + + + has a screen large enough to show the whole installer + có màn hình đủ lớn để hiển thị toàn bộ trình cài đặt + + + + The screen is too small to display the setup program. + Màn hình quá nhỏ để hiển thị chương trình cài đặt. + + + + The screen is too small to display the installer. + Màn hình quá nhỏ để hiển thị trình cài đặt. + + + + HostInfoJob + + + Collecting information about your machine. + Thu thập thông tin về máy của bạn. + + + + IDJob + + + + + + OEM Batch Identifier + Định danh lô OEM + + + + Could not create directories <code>%1</code>. + Không thể tạo thư mục <code> %1 </code>. + + + + Could not open file <code>%1</code>. + Không thể mở được tệp <code> %1 </code>. + + + + Could not write to file <code>%1</code>. + Không thể ghi vào tệp <code> %1 </code>. + + + + InitcpioJob + + + Creating initramfs with mkinitcpio. + Đang tạo initramfs bằng mkinitcpio. + + + + InitramfsJob + + + Creating initramfs. + Đang tạo initramfs. + + + + InteractiveTerminalPage + + + Konsole not installed + Konsole chưa được cài đặt + + + + Please install KDE Konsole and try again! + Vui lòng cài đặt KDE Konsole rồi thử lại! + + + + Executing script: &nbsp;<code>%1</code> + Đang thực thi kịch bản: &nbsp;<code>%1</code> + + + + InteractiveTerminalViewStep + + + Script + Kịch bản + + + + KeyboardPage + + + Set keyboard model to %1.<br/> + Thiết lập bàn phím kiểu %1.<br/> + + + + Set keyboard layout to %1/%2. + Thiết lập bố cục bàn phím thành %1/%2. + + + + KeyboardQmlViewStep + + + Keyboard + Bàn phím + + + + KeyboardViewStep + + + Keyboard + Bàn phím + + + + LCLocaleDialog + + + System locale setting + Cài đặt ngôn ngữ hệ thống + + + + The system locale setting affects the language and character set for some command line user interface elements.<br/>The current setting is <strong>%1</strong>. + Thiết lập ngôn ngữ hệ thống ảnh hưởng tới ngôn ngữ và bộ kí tự của một vài thành phần trong giao diện dòng lệnh cho người dùng.<br/>Thiết lập hiện tại là <strong>%1</strong>. + + + + &Cancel + &Huỷ bỏ + + + + &OK + &OK + + + + LicensePage + + + Form + Biểu mẫu + + + + <h1>License Agreement</h1> + <h1>Điều khoản giấy phép</h1> + + + + I accept the terms and conditions above. + Tôi đồng ý với điều khoản và điều kiện trên. + + + + Please review the End User License Agreements (EULAs). + Vui lòng đọc thoả thuận giấy phép người dùng cuối (EULAs). + + + + This setup procedure will install proprietary software that is subject to licensing terms. + Quy trình thiết lập này sẽ cài đặt phần mềm độc quyền tuân theo các điều khoản cấp phép. + + + + If you do not agree with the terms, the setup procedure cannot continue. + Nếu bạn không đồng ý với các điều khoản, quy trình thiết lập không thể tiếp tục. + + + + This setup procedure can install proprietary software that is subject to licensing terms in order to provide additional features and enhance the user experience. + Quy trình thiết lập này có thể cài đặt phần mềm độc quyền tuân theo các điều khoản cấp phép để cung cấp các tính năng bổ sung và nâng cao trải nghiệm người dùng. + + + + If you do not agree with the terms, proprietary software will not be installed, and open source alternatives will be used instead. + Nếu bạn không đồng ý với các điều khoản, phần mềm độc quyền sẽ không được cài đặt và các giải pháp thay thế nguồn mở sẽ được sử dụng thay thế. + + + + LicenseViewStep + + + License + Giấy phép + + + + LicenseWidget + + + URL: %1 + URL: %1 + + + + <strong>%1 driver</strong><br/>by %2 + %1 is an untranslatable product name, example: Creative Audigy driver + <strong>trình điều khiển %1</strong><br/>bởi %2 + + + + <strong>%1 graphics driver</strong><br/><font color="Grey">by %2</font> + %1 is usually a vendor name, example: Nvidia graphics driver + <strong>trình điều khiển đồ hoạc %1</strong><br/><font color="Grey">bởi %2</font> + + + + <strong>%1 browser plugin</strong><br/><font color="Grey">by %2</font> + <strong>plugin trình duyệt %1</strong><br/><font color="Grey">bởi %2</font> + + + + <strong>%1 codec</strong><br/><font color="Grey">by %2</font> + <strong>%1 codec</strong><br/><font color="Grey">bởi %2</font> + + + + <strong>%1 package</strong><br/><font color="Grey">by %2</font> + <strong>gói %1</strong><br/><font color="Grey">bởi %2</font> + + + + <strong>%1</strong><br/><font color="Grey">by %2</font> + <strong>%1</strong><br/><font color="Grey">bởi %2</font> + + + + File: %1 + Tệp: %1 + + + + Hide license text + Ẩn thông tin giấy phép + + + + Show the license text + Hiện thông tin giấy phép + + + + Open license agreement in browser. + Mở điều khoản giấy phép trên trình duyệt. + + + + LocalePage + + + Region: + Khu vực: + + + + Zone: + Vùng: + + + + + &Change... + &Thay đổi... + + + + LocaleQmlViewStep + + + Location + Vị trí + + + + LocaleViewStep + + + Location + Vị trí + + + + LuksBootKeyFileJob + + + Configuring LUKS key file. + Định cấu hình tệp khóa LUKS. + + + + + No partitions are defined. + Không có phân vùng nào được xác định. + + + + + + Encrypted rootfs setup error + Lỗi thiết lập rootfs mã hóa + + + + Root partition %1 is LUKS but no passphrase has been set. + Phân vùng gốc %1 là LUKS nhưng không có cụm mật khẩu nào được đặt. + + + + Could not create LUKS key file for root partition %1. + Không thể tạo tệp khóa LUKS cho phân vùng gốc %1. + + + + Could not configure LUKS key file on partition %1. + Không thể định cấu hình tệp khóa LUKS trên phân vùng %1. + + + + MachineIdJob + + + Generate machine-id. + Tạo ID máy. + + + + Configuration Error + Lỗi cấu hình + + + + No root mount point is set for MachineId. + Không có điểm gắn kết gốc nào được đặt cho ID máy + + + + Map + + + Timezone: %1 + Múi giờ: %1 + + + + Please select your preferred location on the map so the installer can suggest the locale + and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging + to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming. + Vui lòng chọn vị trí ưa thích của bạn trên bản đồ để trình cài đặt có thể đề xuất ngôn ngữ + và cài đặt múi giờ cho bạn. Bạn có thể tinh chỉnh các cài đặt được đề xuất bên dưới. Tìm kiếm bản đồ bằng cách kéo + để di chuyển và sử dụng các nút +/- để phóng to / thu nhỏ hoặc sử dụng cuộn chuột để phóng to. + + + + NetInstallViewStep + + + + Package selection + Chọn phân vùng + + + + Office software + Phần mềm văn phòng + + + + Office package + Gói văn phòng + + + + Browser software + Phần mềm trình duyệt + + + + Browser package + Gói trình duyệt + + + + Web browser + Trình duyệt web + + + + Kernel + Lõi + + + + Services + Dịch vụ + + + + Login + Đăng nhập + + + + Desktop + Màn hình chính + + + + Applications + Ứng dụng + + + + Communication + Cộng đồng + + + + Development + Phát triển + + + + Office + Văn phòng + + + + Multimedia + Đa phương tiện + + + + Internet + Mạng Internet + + + + Theming + Chủ đề + + + + Gaming + Trò chơi + + + + Utilities + Tiện ích + + + + NotesQmlViewStep + + + Notes + Ghi chú + + + + OEMPage + + + Ba&tch: + &Lô: + + + + <html><head/><body><p>Enter a batch-identifier here. This will be stored in the target system.</p></body></html> + <html><head/><body> <p> Nhập số nhận dạng lô tại đây. Điều này sẽ được lưu trữ trong hệ thống đích. </p> </body> </html> + + + + <html><head/><body><h1>OEM Configuration</h1><p>Calamares will use OEM settings while configuring the target system.</p></body></html> + <html><head/><body> <h1> Cấu hình OEM </h1> <p> Calamares sẽ sử dụng cài đặt OEM trong khi định cấu hình hệ thống đích. </p> </body> </html> + + + + OEMViewStep + + + OEM Configuration + Cấu hình OEM + + + + Set the OEM Batch Identifier to <code>%1</code>. + Đặt số nhận dạng lô OEM thành <code> %1 </code>. + + + + Offline + + + Select your preferred Region, or use the default one based on your current location. + Chọn khu vực ưa thích của bạn hoặc sử dụng khu vực mặc định dựa trên vị trí hiện tại của bạn. + + + + + + Timezone: %1 + Múi giờ: %1 + + + + Select your preferred Zone within your Region. + Chọn vùng ưa thích của bạn trong khu vực của bạn. + + + + Zones + Vùng + + + + You can fine-tune Language and Locale settings below. + Bạn có thể tinh chỉnh cài đặt Ngôn ngữ và Bản địa bên dưới. + + + + PWQ + + + Password is too short + Mật khẩu quá ngắn + + + + Password is too long + Mật khẩu quá dài + + + + Password is too weak + Mật khẩu quá yếu + + + + Memory allocation error when setting '%1' + Lỗi phân bổ bộ nhớ khi cài đặt '%1' + + + + Memory allocation error + Lỗi phân bổ bộ nhớ + + + + The password is the same as the old one + Mật khẩu giống với mật khẩu cũ + + + + The password is a palindrome + Mật khẩu là chuỗi đối xứng + + + + The password differs with case changes only + Mật khẩu chỉ khác khi thay đổi chữ hoa chữ thường + + + + The password is too similar to the old one + Mật khẩu giống mật khẩu cũ + + + + The password contains the user name in some form + Mật khẩu chứa tên người dùng ở một số dạng + + + + The password contains words from the real name of the user in some form + Mật khẩu chứa các từ từ tên thật của người dùng dưới một số hình thức + + + + The password contains forbidden words in some form + Mật khẩu chứa các từ bị cấm dưới một số hình thức + + + + The password contains less than %1 digits + Mật khẩu chứa ít hơn %1 ký tự + + + + The password contains too few digits + Mật khẩu chứa quá ít ký tự + + + + The password contains less than %1 uppercase letters + Mật khẩu có ít nhất %1 chữ viết hoa + + + + The password contains too few uppercase letters + Mật khẩu chứa quá ít chữ hoa + + + + The password contains less than %1 lowercase letters + Mật khẩu chứa ít hơn %1 chữ thường + + + + The password contains too few lowercase letters + Mật khẩu chứa quá ít chữ thường + + + + The password contains less than %1 non-alphanumeric characters + Mật khẩu chứa ít hơn %1 ký tự không phải chữ và số + + + + The password contains too few non-alphanumeric characters + Mật khẩu chứa quá ít ký tự không phải chữ và số + + + + The password is shorter than %1 characters + Mật khẩu ngắn hơn %1 ký tự + + + + The password is too short + Mật khẩu quá ngắn + + + + The password is just rotated old one + Mật khẩu vừa được xoay vòng cũ + + + + The password contains less than %1 character classes + Mật khẩu chứa ít hơn %1 lớp ký tự + + + + The password does not contain enough character classes + Mật khẩu không chứa đủ các lớp ký tự + + + + The password contains more than %1 same characters consecutively + Mật khẩu chứa nhiều hơn %1 ký tự giống nhau liên tiếp + + + + The password contains too many same characters consecutively + Mật khẩu chứa quá nhiều ký tự giống nhau liên tiếp + + + + The password contains more than %1 characters of the same class consecutively + Mật khẩu chứa nhiều hơn %1 ký tự của cùng một lớp liên tiếp + + + + The password contains too many characters of the same class consecutively + Mật khẩu chứa quá nhiều ký tự của cùng một lớp liên tiếp + + + + The password contains monotonic sequence longer than %1 characters + Mật khẩu chứa chuỗi đơn điệu dài hơn %1 ký tự + + + + The password contains too long of a monotonic character sequence + Mật khẩu chứa một chuỗi ký tự đơn điệu quá dài + + + + No password supplied + Chưa cung cấp mật khẩu + + + + Cannot obtain random numbers from the RNG device + Không thể lấy số ngẫu nhiên từ thiết bị RNG + + + + Password generation failed - required entropy too low for settings + Tạo mật khẩu không thành công - yêu cầu entropy quá thấp để cài đặt + + + + The password fails the dictionary check - %1 + Mật khẩu không kiểm tra được từ điển - %1 + + + + The password fails the dictionary check + Mật khẩu không kiểm tra được từ điển + + + + Unknown setting - %1 + Cài đặt không xác định - %1 + + + + Unknown setting + Cài đặt không xác định + + + + Bad integer value of setting - %1 + Giá trị số nguyên không hợp lệ của cài đặt - %1 + + + + Bad integer value + Giá trị số nguyên không hợp lệ + + + + Setting %1 is not of integer type + Cài đặt %1 không thuộc kiểu số nguyên + + + + Setting is not of integer type + Cài đặt không thuộc kiểu số nguyên + + + + Setting %1 is not of string type + Cài đặt %1 không thuộc loại chuỗi + + + + Setting is not of string type + Cài đặt không thuộc loại chuỗi + + + + Opening the configuration file failed + Không mở được tệp cấu hình + + + + The configuration file is malformed + Tệp cấu hình không đúng định dạng + + + + Fatal failure + Thất bại nghiêm trọng + + + + Unknown error + Lỗi không xác định + + + + Password is empty + Mật khẩu trống + + + + PackageChooserPage + + + Form + Biểu mẫu + + + + Product Name + Tên sản phẩm + + + + TextLabel + Nhãn văn bản + + + + Long Product Description + Mô tả đầy đủ sản phẩm + + + + Package Selection + Lựa chọn gói + + + + Please pick a product from the list. The selected product will be installed. + Vui lòng chọn một sản phẩm từ danh sách. Sản phẩm đã chọn sẽ được cài đặt. + + + + PackageChooserViewStep + + + Packages + Gói + + + + PackageModel + + + Name + Tên + + + + Description + Mô tả + + + + Page_Keyboard + + + Form + Biểu mẫu + + + + Keyboard Model: + Mẫu bàn phím: + + + + Type here to test your keyboard + Gõ vào đây để thử bàn phím + + + + Page_UserSetup + + + Form + Mẫu + + + + What is your name? + Hãy cho Vigo biết tên đầy đủ của bạn? + + + + Your Full Name + Tên đầy đủ + + + + What name do you want to use to log in? + Bạn sẽ dùng tên nào để đăng nhập vào máy tính? + + + + login + Tên đăng nhập + + + + What is the name of this computer? + Tên máy tính này là? + + + + <small>This name will be used if you make the computer visible to others on a network.</small> + <small>Tên này được dùng nếu máy tính được nhìn thấy trong mạng.</small> + + + + Computer Name + Tên máy + + + + Choose a password to keep your account safe. + Chọn một mật khẩu để giữ an toàn cho tài khoản của bạn. + + + + + <small>Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals.</small> + <small>Nhập mật khẩu hai lần giống nhau để kiểm tra nếu gõ sai.Một mật khẩu tốt được kết hợp giữ ký tự, số và ký tự đặc biệt; ít nhất 8 ký tự và nên được thay đổi định kỳ.</small> + + + + + Password + Mật khẩu + + + + + Repeat Password + Nhập lại mật khẩu + + + + When this box is checked, password-strength checking is done and you will not be able to use a weak password. + Khi chọn mục này, bạn có thể chọn mật khẩu yếu. + + + + Require strong passwords. + Yêu cầu mật khẩu mạnh. + + + + Log in automatically without asking for the password. + Tự đăng nhật không cần mật khẩu. + + + + Use the same password for the administrator account. + Dùng cùng một mật khẩu cho tài khoản quản trị. + + + + Choose a password for the administrator account. + Chọn một mật khẩu cho tài khoản quản trị. + + + + + <small>Enter the same password twice, so that it can be checked for typing errors.</small> + <small>Nhập mật khẩu hai lần giống nhau để kiểm tra nếu gõ sai.</small> + + + + PartitionLabelsView + + + Root + Gốc + + + + Home + Nhà + + + + Boot + Khởi động + + + + EFI system + Hệ thống EFI + + + + Swap + Hoán đổi + + + + New partition for %1 + Phân vùng mới cho %1 + + + + New partition + Phân vùng mới + + + + %1 %2 + size[number] filesystem[name] + %1 %2 + + + + PartitionModel + + + + Free Space + Không gian trống + + + + + New partition + Phân vùng mới + + + + Name + Tên + + + + File System + Tập tin hệ thống + + + + Mount Point + Điểm gắn kết + + + + Size + Kích cỡ + + + + PartitionPage + + + Form + Biểu mẫu + + + + Storage de&vice: + Thiết &bị lưu trữ: + + + + &Revert All Changes + &Hoàn tác tất cả thay đổi + + + + New Partition &Table + Phân vùng &Bảng mới + + + + Cre&ate + &Tạo + + + + &Edit + &Sửa + + + + &Delete + &Xóa + + + + New Volume Group + Nhóm ổ đĩa mới + + + + Resize Volume Group + Thay đổi kích thước nhóm ổ đĩa + + + + Deactivate Volume Group + Hủy kích hoạt nhóm ổ đĩa + + + + Remove Volume Group + Xóa nhóm ổ đĩa + + + + I&nstall boot loader on: + &Cài đặt bộ tải khởi động trên: + + + + Are you sure you want to create a new partition table on %1? + Bạn có chắc chắn muốn tạo một bảng phân vùng mới trên %1 không? + + + + Can not create new partition + Không thể tạo phân vùng mới + + + + The partition table on %1 already has %2 primary partitions, and no more can be added. Please remove one primary partition and add an extended partition, instead. + Bảng phân vùng trên %1 đã có %2 phân vùng chính và không thể thêm được nữa. Vui lòng xóa một phân vùng chính và thêm một phân vùng mở rộng, thay vào đó. + + + + PartitionViewStep + + + Gathering system information... + Thu thập thông tin hệ thống ... + + + + Partitions + Phân vùng + + + + Install %1 <strong>alongside</strong> another operating system. + Cài đặt %1 <strong> cùng với </strong> hệ điều hành khác. + + + + <strong>Erase</strong> disk and install %1. + <strong> Xóa </strong> đĩa và cài đặt %1. + + + + <strong>Replace</strong> a partition with %1. + <strong>thay thế</strong> một phân vùng với %1. + + + + <strong>Manual</strong> partitioning. + Phân vùng <strong> thủ công </strong>. + + + + Install %1 <strong>alongside</strong> another operating system on disk <strong>%2</strong> (%3). + Cài đặt %1 <strong> cùng với </strong> hệ điều hành khác trên đĩa <strong>%2</strong> (%3). + + + + <strong>Erase</strong> disk <strong>%2</strong> (%3) and install %1. + <strong> Xóa </strong> đĩa <strong>%2 </strong> (%3) và cài đặt %1. + + + + <strong>Replace</strong> a partition on disk <strong>%2</strong> (%3) with %1. + <strong> Thay thế </strong> phân vùng trên đĩa <strong>%2 </strong> (%3) bằng %1. + + + + <strong>Manual</strong> partitioning on disk <strong>%1</strong> (%2). + Phân vùng <strong> thủ công </strong> trên đĩa <strong>%1 </strong> (%2). + + + + Disk <strong>%1</strong> (%2) + Đĩa <strong>%1</strong> (%2) + + + + Current: + Hiện tại: + + + + After: + Sau: + + + + No EFI system partition configured + Không có hệ thống phân vùng EFI được cài đặt + + + + An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a FAT32 filesystem with the <strong>%3</strong> flag enabled and mount point <strong>%2</strong>.<br/><br/>You can continue without setting up an EFI system partition but your system may fail to start. + Cần có phân vùng hệ thống EFI để khởi động %1. <br/> <br/> Để định cấu hình phân vùng hệ thống EFI, hãy quay lại và chọn hoặc tạo hệ thống tệp FAT32 với cờ <strong> %3 </strong> được bật và gắn kết point <strong> %2 </strong>. <br/> <br/> Bạn có thể tiếp tục mà không cần thiết lập phân vùng hệ thống EFI nhưng hệ thống của bạn có thể không khởi động được. + + + + An EFI system partition is necessary to start %1.<br/><br/>A partition was configured with mount point <strong>%2</strong> but its <strong>%3</strong> flag is not set.<br/>To set the flag, go back and edit the partition.<br/><br/>You can continue without setting the flag but your system may fail to start. + Một phân vùng hệ thống EFI là cần thiết để bắt đầu %1. <br/> <br/> Một phân vùng đã được định cấu hình với điểm gắn kết <strong> %2 </strong> nhưng cờ <strong> %3 </strong> của nó không được đặt . <br/> Để đặt cờ, hãy quay lại và chỉnh sửa phân vùng. <br/> <br/> Bạn có thể tiếp tục mà không cần đặt cờ nhưng hệ thống của bạn có thể không khởi động được. + + + + EFI system partition flag not set + Cờ phân vùng hệ thống EFI chưa được đặt + + + + Option to use GPT on BIOS + Lựa chọn dùng GPT trên BIOS + + + + A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.<br/><br/>To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the <strong>bios_grub</strong> flag enabled.<br/><br/>An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT. + Bảng phân vùng GPT là lựa chọn tốt nhất cho tất cả các hệ thống. Trình cài đặt này cũng hỗ trợ thiết lập như vậy cho các hệ thống BIOS. <br/> <br/> Để định cấu hình bảng phân vùng GPT trên BIOS, (nếu chưa thực hiện xong) hãy quay lại và đặt bảng phân vùng thành GPT, tiếp theo tạo 8 MB phân vùng chưa định dạng với cờ <strong> bios_grub </strong> được bật. <br/> <br/> Cần có phân vùng 8 MB chưa được định dạng để khởi động %1 trên hệ thống BIOS có GPT. + + + + Boot partition not encrypted + Phân vùng khởi động không được mã hóa + + + + A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.<br/><br/>There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.<br/>You may continue if you wish, but filesystem unlocking will happen later during system startup.<br/>To encrypt the boot partition, go back and recreate it, selecting <strong>Encrypt</strong> in the partition creation window. + Một phân vùng khởi động riêng biệt đã được thiết lập cùng với một phân vùng gốc được mã hóa, nhưng phân vùng khởi động không được mã hóa. <br/> <br/> Có những lo ngại về bảo mật với loại thiết lập này, vì các tệp hệ thống quan trọng được lưu giữ trên một phân vùng không được mã hóa . <br/> Bạn có thể tiếp tục nếu muốn, nhưng việc mở khóa hệ thống tệp sẽ diễn ra sau trong quá trình khởi động hệ thống. <br/> Để mã hóa phân vùng khởi động, hãy quay lại và tạo lại nó, chọn <strong> Mã hóa </strong> trong phân vùng cửa sổ tạo. + + + + has at least one disk device available. + có sẵn ít nhất một thiết bị đĩa. + + + + There are no partitions to install on. + Không có phân vùng để cài đặt. + + + + PlasmaLnfJob + + + Plasma Look-and-Feel Job + Công việc Plasma Look-and-Feel + + + + + Could not select KDE Plasma Look-and-Feel package + Không thể chọn gói KDE Plasma Look-and-Feel + + + + PlasmaLnfPage + + + Form + Biểu mẫu + + + + Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is set up. Clicking on a look-and-feel selection will give you a live preview of that look-and-feel. + Vui lòng chọn giao diện cho Máy tính để bàn KDE Plasma. Bạn cũng có thể bỏ qua bước này và định cấu hình giao diện sau khi hệ thống được thiết lập. Nhấp vào lựa chọn giao diện sẽ cung cấp cho bạn bản xem trước trực tiếp của giao diện đó. + + + + Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is installed. Clicking on a look-and-feel selection will give you a live preview of that look-and-feel. + Vui lòng chọn giao diện cho Máy tính để bàn KDE Plasma. Bạn cũng có thể bỏ qua bước này và định cấu hình giao diện sau khi hệ thống được thiết lập. Nhấp vào lựa chọn giao diện sẽ cung cấp cho bạn bản xem trước trực tiếp của giao diện đó. + + + + PlasmaLnfViewStep + + + Look-and-Feel + Look-and-Feel + + + + PreserveFiles + + + Saving files for later ... + Đang lưu tập tin để dùng sau ... + + + + No files configured to save for later. + Không có tệp nào được định cấu hình để lưu sau này. + + + + Not all of the configured files could be preserved. + Không phải tất cả các tệp đã định cấu hình đều có thể được giữ nguyên. + + + + ProcessResult + + + +There was no output from the command. + +Không có đầu ra từ lệnh. + + + + +Output: + + +Đầu ra: + + + + + External command crashed. + Lệnh bên ngoài bị lỗi. + + + + Command <i>%1</i> crashed. + Lệnh <i>%1</i> bị lỗi. + + + + External command failed to start. + Lệnh ngoài không thể bắt đầu. + + + + Command <i>%1</i> failed to start. + Lệnh <i>%1</i> không thể bắt đầu. + + + + Internal error when starting command. + Lỗi nội bộ khi bắt đầu lệnh. + + + + Bad parameters for process job call. + Tham số không hợp lệ cho lệnh gọi công việc của quy trình. + + + + External command failed to finish. + Không thể hoàn tất lệnh bên ngoài. + + + + Command <i>%1</i> failed to finish in %2 seconds. + Lệnh <i>%1</i> không thể hoàn thành trong %2 giây. + + + + External command finished with errors. + Lệnh bên ngoài kết thúc với lỗi. + + + + Command <i>%1</i> finished with exit code %2. + Lệnh <i>%1</i> hoàn thành với lỗi %2. + + + + QObject + + + %1 (%2) + %1 (%2) + + + + unknown + không xác định + + + + extended + gia tăng + + + + unformatted + không định dạng + + + + swap + hoán đổi + + + + Default Keyboard Model + Mẫu bàn phím mặc định + + + + + Default + Mặc định + + + + + + + File not found + Không tìm thấy tập tin + + + + Path <pre>%1</pre> must be an absolute path. + Đường dẫn <pre>%1</pre> phải là đường dẫn tuyệt đối. + + + + Directory not found + Thư mục không tìm thấy + + + + + Could not create new random file <pre>%1</pre>. + Không thể tạo tập tin ngẫu nhiên <pre>%1</pre>. + + + + No product + Không có sản phẩm + + + + No description provided. + Không có mô tả được cung cấp. + + + + (no mount point) + (không có điểm gắn kết) + + + + Unpartitioned space or unknown partition table + Không gian chưa được phân vùng hoặc bảng phân vùng không xác định + + + + Recommended + + + <p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/> + Setup can continue, but some features might be disabled.</p> + <p> Máy tính này không đáp ứng một số yêu cầu được đề xuất để thiết lập %1. <br/> + Có thể tiếp tục thiết lập nhưng một số tính năng có thể bị tắt. </p> + + + + RemoveUserJob + + + Remove live user from target system + Xóa người dùng trực tiếp khỏi hệ thống đích + + + + RemoveVolumeGroupJob + + + + Remove Volume Group named %1. + Xóa nhóm ổ đĩa có tên %1. + + + + Remove Volume Group named <strong>%1</strong>. + Xóa nhóm ổ đĩa có tên <strong>%1</strong>. + + + + The installer failed to remove a volume group named '%1'. + Trình cài đặt không xóa được nhóm ổ đĩa có tên '%1'. + + + + ReplaceWidget + + + Form + Biểu mẫu + + + + Select where to install %1.<br/><font color="red">Warning: </font>this will delete all files on the selected partition. + Chọn nơi cài đặt %1. <br/> <font color = "red"> Cảnh báo: </font> điều này sẽ xóa tất cả các tệp trên phân vùng đã chọn. + + + + The selected item does not appear to be a valid partition. + Mục đã chọn dường như không phải là một phân vùng hợp lệ. + + + + %1 cannot be installed on empty space. Please select an existing partition. + %1 không thể được cài đặt trên không gian trống. Vui lòng chọn một phân vùng hiện có. + + + + %1 cannot be installed on an extended partition. Please select an existing primary or logical partition. + %1 không thể được cài đặt trên một phân vùng mở rộng. Vui lòng chọn phân vùng chính hoặc phân vùng logic hiện có. + + + + %1 cannot be installed on this partition. + %1 không thể cài đặt trên phân vùng này. + + + + Data partition (%1) + Phân vùng dữ liệu (%1) + + + + Unknown system partition (%1) + Phân vùng hệ thống không xác định (%1) + + + + %1 system partition (%2) + %1 phân vùng hệ thống (%2) + + + + <strong>%4</strong><br/><br/>The partition %1 is too small for %2. Please select a partition with capacity at least %3 GiB. + <strong> %4 </strong> <br/> <br/> Phân vùng %1 quá nhỏ đối với %2. Vui lòng chọn một phân vùng có dung lượng ít nhất là %3 GiB. + + + + <strong>%2</strong><br/><br/>An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. + <strong> %2 </strong> <br/> <br/> Không thể tìm thấy phân vùng hệ thống EFI ở bất kỳ đâu trên hệ thống này. Vui lòng quay lại và sử dụng phân vùng thủ công để thiết lập %1. + + + + + + <strong>%3</strong><br/><br/>%1 will be installed on %2.<br/><font color="red">Warning: </font>all data on partition %2 will be lost. + <strong> %3 </strong> <br/> <br/> %1 sẽ được cài đặt trên %2. <br/> <font color = "red"> Cảnh báo: </font> tất cả dữ liệu trên phân vùng %2 sẽ bị mất. + + + + The EFI system partition at %1 will be used for starting %2. + Phân vùng hệ thống EFI tại %1 sẽ được sử dụng để bắt đầu %2. + + + + EFI system partition: + Phân vùng hệ thống EFI: + + + + Requirements + + + <p>This computer does not satisfy the minimum requirements for installing %1.<br/> + Installation cannot continue.</p> + <p> Máy tính này không đáp ứng các yêu cầu tối thiểu để cài đặt %1. <br/> + Không thể tiếp tục cài đặt. </p> + + + + <p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/> + Setup can continue, but some features might be disabled.</p> + <p> Máy tính này không đáp ứng một số yêu cầu được đề xuất để thiết lập %1. <br/> + Có thể tiếp tục thiết lập nhưng một số tính năng có thể bị tắt. </p> + + + + ResizeFSJob + + + Resize Filesystem Job + Thay đổi kích thước tệp công việc hệ thống + + + + Invalid configuration + Cấu hình không hợp lệ + + + + The file-system resize job has an invalid configuration and will not run. + Công việc thay đổi kích thước hệ thống tệp có cấu hình không hợp lệ và sẽ không chạy. + + + + KPMCore not Available + KPMCore không khả dụng + + + + Calamares cannot start KPMCore for the file-system resize job. + Calamares không thể khởi động KPMCore cho công việc thay đổi kích thước hệ thống tệp. + + + + + + + + Resize Failed + Thay đổi kích thước không thành công + + + + The filesystem %1 could not be found in this system, and cannot be resized. + Không thể tìm thấy tệp hệ thống %1 trong hệ thống này và không thể thay đổi kích thước. + + + + The device %1 could not be found in this system, and cannot be resized. + Không thể tìm thấy thiết bị %1 trong hệ thống này và không thể thay đổi kích thước. + + + + + The filesystem %1 cannot be resized. + Không thể thay đổi kích thước tệp hệ thống %1. + + + + + The device %1 cannot be resized. + Không thể thay đổi kích thước thiết bị %1. + + + + The filesystem %1 must be resized, but cannot. + Hệ thống tệp %1 phải được thay đổi kích thước, nhưng không thể. + + + + The device %1 must be resized, but cannot + Thiết bị %1 phải được thay đổi kích thước, nhưng không thể + + + + ResizePartitionJob + + + Resize partition %1. + Đổi kích thước phân vùng %1. + + + + Resize <strong>%2MiB</strong> partition <strong>%1</strong> to <strong>%3MiB</strong>. + Thay đổi kích thước <strong>%2MiB</strong> phân vùng <strong>%1</strong> toùng <strong>%3đếnMiB</strong>. + + + + Resizing %2MiB partition %1 to %3MiB. + Thay đổi %2MiB phân vùng %1 thành %3MiB. + + + + The installer failed to resize partition %1 on disk '%2'. + Thất bại trong việc thay đổi kích thước phân vùng %1 trên đĩa '%2'. + + + + ResizeVolumeGroupDialog + + + Resize Volume Group + Thay đổi kích thước nhóm ổ đĩa + + + + ResizeVolumeGroupJob + + + + Resize volume group named %1 from %2 to %3. + Thay đổi kích thước nhóm ổ đĩa có tên %1 từ %2 thành %3. + + + + Resize volume group named <strong>%1</strong> from <strong>%2</strong> to <strong>%3</strong>. + Thay đổi kích thước nhóm ổ đĩa có tên <strong> %1 </strong> từ <strong> %2 </strong> thành <strong> %3 </strong>. + + + + The installer failed to resize a volume group named '%1'. + Trình cài đặt không thể thay đổi kích thước một nhóm ổ đĩa có tên ' %1'. + + + + ResultsListDialog + + + For best results, please ensure that this computer: + Để có kết quả tốt nhất, hãy đảm bảo rằng máy tính này: + + + + System requirements + Yêu cầu hệ thống + + + + ResultsListWidget + + + This computer does not satisfy the minimum requirements for setting up %1.<br/>Setup cannot continue. <a href="#details">Details...</a> + Máy tính này không đáp ứng các yêu cầu tối thiểu để thiết lập %1. <br/> Không thể tiếp tục thiết lập. <a href="#details"> Chi tiết ... </a> + + + + This computer does not satisfy the minimum requirements for installing %1.<br/>Installation cannot continue. <a href="#details">Details...</a> + Máy tính này không đáp ứng các yêu cầu tối thiểu để cài đặt %1. <br/> Không thể tiếp tục cài đặt. <a href="#details"> Chi tiết ... </a> + + + + This computer does not satisfy some of the recommended requirements for setting up %1.<br/>Setup can continue, but some features might be disabled. + Máy tính này không đáp ứng một số yêu cầu được khuyến nghị để thiết lập %1. <br/> Quá trình thiết lập có thể tiếp tục nhưng một số tính năng có thể bị tắt. + + + + This computer does not satisfy some of the recommended requirements for installing %1.<br/>Installation can continue, but some features might be disabled. + Máy tính này không đáp ứng một số yêu cầu được khuyến nghị để cài đặt %1. <br/> Quá trình cài đặt có thể tiếp tục, nhưng một số tính năng có thể bị tắt. + + + + This program will ask you some questions and set up %2 on your computer. + Chương trình này sẽ hỏi bạn một số câu hỏi và thiết lập %2 trên máy tính của bạn. + + + + ScanningDialog + + + Scanning storage devices... + Quét thiết bị lưu trữ... + + + + Partitioning + Đang phân vùng + + + + SetHostNameJob + + + Set hostname %1 + Đặt tên máy %1 + + + + Set hostname <strong>%1</strong>. + Đặt tên máy <strong>%1</strong>. + + + + Setting hostname %1. + Đặt tên máy %1. + + + + + Internal Error + Lỗi bên trong + + + + + Cannot write hostname to target system + Không thể ghi tên máy chủ vào hệ thống đích + + + + SetKeyboardLayoutJob + + + Set keyboard model to %1, layout to %2-%3 + Cài đặt bàn phím kiểu %1, bố cục %2-%3 + + + + Failed to write keyboard configuration for the virtual console. + Lỗi khi ghi cấu hình bàn phím cho virtual console. + + + + + + Failed to write to %1 + Lỗi khi ghi vào %1 + + + + Failed to write keyboard configuration for X11. + Lỗi khi ghi cấu hình bàn phím cho X11. + + + + Failed to write keyboard configuration to existing /etc/default directory. + Lỗi khi ghi cấu hình bàn phím vào thư mục /etc/default. + + + + SetPartFlagsJob + + + Set flags on partition %1. + Chọn cờ trong phân vùng %1. + + + + Set flags on %1MiB %2 partition. + Chọn cờ %1MiB %2 phân vùng. + + + + Set flags on new partition. + Chọn cờ trong phân vùng mới. + + + + Clear flags on partition <strong>%1</strong>. + Xóa cờ trong phân vùng<strong>%1</strong>. + + + + Clear flags on %1MiB <strong>%2</strong> partition. + Xóa cờ trong %1MiB <strong>%2</strong> phân vùng. + + + + Clear flags on new partition. + Xóa cờ trong phân vùng mới. + + + + Flag partition <strong>%1</strong> as <strong>%2</strong>. + Cờ phân vùng <strong>%1</strong> như <strong>%2</strong>. + + + + Flag %1MiB <strong>%2</strong> partition as <strong>%3</strong>. + Cờ %1MiB <strong>%2</strong> phân vùng như <strong>%3</strong>. + + + + Flag new partition as <strong>%1</strong>. + Cờ phân vùng mới như <strong>%1</strong>. + + + + Clearing flags on partition <strong>%1</strong>. + Đang xóa cờ trên phân vùng <strong>%1</strong>. + + + + Clearing flags on %1MiB <strong>%2</strong> partition. + Đang xóa cờ trên %1MiB <strong>%2</strong> phân vùng. + + + + Clearing flags on new partition. + Đang xóa cờ trên phân vùng mới. + + + + Setting flags <strong>%2</strong> on partition <strong>%1</strong>. + Chọn cờ <strong>%2</strong> trong phân vùng <strong>%1</strong>. + + + + Setting flags <strong>%3</strong> on %1MiB <strong>%2</strong> partition. + Chọn cờ <strong>%3</strong> trong %1MiB <strong>%2</strong> phân vùng. + + + + Setting flags <strong>%1</strong> on new partition. + Chọn cờ <strong>%1</strong> trong phân vùng mới. + + + + The installer failed to set flags on partition %1. + Không thể tạo cờ cho phân vùng %1. + + + + SetPasswordJob + + + Set password for user %1 + Tạo mật khẩu người dùng %1 + + + + Setting password for user %1. + Đang tạo mật khẩu người dùng %1. + + + + Bad destination system path. + Đường dẫn hệ thống đích không hợp lệ. + + + + rootMountPoint is %1 + Điểm gắn kết gốc là %1 + + + + Cannot disable root account. + Không thể vô hiệu hoá tài khoản quản trị. + + + + passwd terminated with error code %1. + passwd bị kết thúc với mã lỗi %1. + + + + Cannot set password for user %1. + Không thể đặt mật khẩu cho người dùng %1. + + + + usermod terminated with error code %1. + usermod bị chấm dứt với mã lỗi %1. + + + + SetTimezoneJob + + + Set timezone to %1/%2 + Đặt múi giờ thành %1/%2 + + + + Cannot access selected timezone path. + Không thể truy cập đường dẫn múi giờ đã chọn. + + + + Bad path: %1 + Đường dẫn sai: %1 + + + + Cannot set timezone. + Không thể cài đặt múi giờ. + + + + Link creation failed, target: %1; link name: %2 + Không tạo được liên kết, target: %1; tên liên kết: %2 + + + + Cannot set timezone, + Không thể cài đặt múi giờ + + + + Cannot open /etc/timezone for writing + Không thể mở để viết vào /etc/timezone + + + + ShellProcessJob + + + Shell Processes Job + Shell Xử lý Công việc + + + + SlideCounter + + + %L1 / %L2 + slide counter, %1 of %2 (numeric) + %L1 / %L2 + + + + SummaryPage + + + This is an overview of what will happen once you start the setup procedure. + Đây là tổng quan về những gì sẽ xảy ra khi bạn bắt đầu quy trình thiết lập. + + + + This is an overview of what will happen once you start the install procedure. + Đây là tổng quan về những gì sẽ xảy ra khi bạn bắt đầu quy trình cài đặt. + + + + SummaryViewStep + + + Summary + Tổng quan + + + + TrackingInstallJob + + + Installation feedback + Phản hồi cài đặt + + + + Sending installation feedback. + Gửi phản hồi cài đặt. + + + + Internal error in install-tracking. + Lỗi nội bộ trong theo dõi cài đặt. + + + + HTTP request timed out. + Yêu cầu HTTP đã hết thời gian chờ. + + + + TrackingKUserFeedbackJob + + + KDE user feedback + Người dùng KDE phản hồi + + + + Configuring KDE user feedback. + Định cấu hình phản hồi của người dùng KDE. + + + + + Error in KDE user feedback configuration. + Lỗi trong cấu hình phản hồi của người dùng KDE. + + + + Could not configure KDE user feedback correctly, script error %1. + Không thể định cấu hình phản hồi của người dùng KDE một cách chính xác, lỗi tập lệnh %1. + + + + Could not configure KDE user feedback correctly, Calamares error %1. + Không thể định cấu hình phản hồi của người dùng KDE một cách chính xác, lỗi Calamares %1. + + + + TrackingMachineUpdateManagerJob + + + Machine feedback + Phản hồi máy + + + + Configuring machine feedback. + Cấu hình phản hồi máy. + + + + + Error in machine feedback configuration. + Lỗi cấu hình phản hồi máy. + + + + Could not configure machine feedback correctly, script error %1. + Không thể cấu hình phản hồi máy chính xác, kịch bản lỗi %1. + + + + Could not configure machine feedback correctly, Calamares error %1. + Không thể cấu hình phản hồi máy chính xác, lỗi %1. + + + + TrackingPage + + + Form + Biểu mẫu + + + + Placeholder + Trình giữ chỗ + + + + <html><head/><body><p>Click here to send <span style=" font-weight:600;">no information at all</span> about your installation.</p></body></html> + <html><head/><body><p>Nhấp vào đây để gửi <span style=" font-weight:600;">không có thông tin nào</span> về cài đặt của bạn.</p></body></html> + + + + <html><head/><body><p><a href="placeholder"><span style=" text-decoration: underline; color:#2980b9;">Click here for more information about user feedback</span></a></p></body></html> + <html><head/><body><p><a href="placeholder"><span style=" text-decoration: underline; color:#2980b9;">Bấm vào đây để biết thêm thông tin về phản hồi của người dùng</span></a></p></body></html> + + + + Tracking helps %1 to see how often it is installed, what hardware it is installed on and which applications are used. To see what will be sent, please click the help icon next to each area. + Theo dõi giúp %1 biết tần suất cài đặt, phần cứng được cài đặt trên phần cứng nào và ứng dụng nào được sử dụng. Để xem những gì sẽ được gửi, vui lòng nhấp vào biểu tượng trợ giúp bên cạnh mỗi khu vực. + + + + By selecting this you will send information about your installation and hardware. This information will only be sent <b>once</b> after the installation finishes. + Bằng cách chọn này, bạn sẽ gửi thông tin về cài đặt và phần cứng của mình. Thông tin này sẽ chỉ được gửi <b> một lần </b> sau khi quá trình cài đặt kết thúc. + + + + By selecting this you will periodically send information about your <b>machine</b> installation, hardware and applications, to %1. + Bằng cách chọn này, bạn sẽ định kỳ gửi thông tin về cài đặt <b> máy </b>, phần cứng và ứng dụng của mình cho %1. + + + + By selecting this you will regularly send information about your <b>user</b> installation, hardware, applications and application usage patterns, to %1. + Bằng cách chọn này, bạn sẽ thường xuyên gửi thông tin về cài đặt <b> người dùng </b>, phần cứng, ứng dụng và các kiểu sử dụng ứng dụng cho %1. + + + + TrackingViewStep + + + Feedback + Phản hồi + + + + UsersPage + + + <small>If more than one person will use this computer, you can create multiple accounts after setup.</small> + <small> Nếu nhiều người cùng sử dụng máy tính này, bạn có thể tạo nhiều tài khoản sau khi thiết lập. </small> + + + + <small>If more than one person will use this computer, you can create multiple accounts after installation.</small> + <small> Nếu nhiều người cùng sử dụng máy tính này, bạn có thể tạo nhiều tài khoản sau khi cài đặt. </small> + + + + UsersQmlViewStep + + + Users + Người dùng + + + + UsersViewStep + + + Users + Người dùng + + + + VariantModel + + + Key + Column header for key/value + Khóa + + + + Value + Column header for key/value + Giá trị + + + + VolumeGroupBaseDialog + + + Create Volume Group + Tạo nhóm ổ đĩa + + + + List of Physical Volumes + Danh sách các đĩa vật lý + + + + Volume Group Name: + Tên nhóm ổ đĩa: + + + + Volume Group Type: + Loại nhóm ổ đĩa: + + + + Physical Extent Size: + Kích thước phạm vi vật lý: + + + + MiB + MiB + + + + Total Size: + Tổng kích thước: + + + + Used Size: + Đã dùng: + + + + Total Sectors: + Tổng số Sec-tơ: + + + + Quantity of LVs: + Số lượng của LVs: + + + + WelcomePage + + + Form + Biểu mẫu + + + + + Select application and system language + Chọn ngôn ngữ ứng dụng và hệ thống + + + + &About + &Giới thiệu + + + + Open donations website + Mở trang web ủng hộ + + + + &Donate + Ủng &hộ + + + + Open help and support website + Mở trang web trợ giúp + + + + &Support + &Hỗ trợ + + + + Open issues and bug-tracking website + Mở trang web theo dõi lỗi và vấn đề + + + + &Known issues + &Vấn đề đã biết + + + + Open release notes website + Mở trang web ghi chú phát hành + + + + &Release notes + &Ghi chú phát hành + + + + <h1>Welcome to the Calamares setup program for %1.</h1> + <h1>Chào mừng đến với chương trình Calamares để thiết lập cho %1.</h1> + + + + <h1>Welcome to %1 setup.</h1> + <h1>Chào mừng đến với thiết lập %1.</h1> + + + + <h1>Welcome to the Calamares installer for %1.</h1> + <h1>Chào mừng đến với chương trình Calamares để cài đặt cho %1.</h1> + + + + <h1>Welcome to the %1 installer.</h1> + <h1>Chào mừng đến với bộ cài đặt %1.</h1> + + + + %1 support + Hỗ trợ %1 + + + + About %1 setup + Về thiết lập %1 + + + + About %1 installer + Về bộ cài đặt %1 + + + + <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. + <h1>%1</h1><br/><strong>%2<br/>cho %3</strong><br/><br/>Bản quyền 2014-2017 bởi Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Bản quyền 2017-2020 bởi Adriaan de Groot &lt;groot@kde.org&gt;<br/>Cám ơn <a href="https://calamares.io/team/">đội ngũ Calamares</a> và <a href="https://www.transifex.com/calamares/calamares/">các dịch giả của Calamares</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> được tài trợ bởi <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. + + + + WelcomeQmlViewStep + + + Welcome + Chào mừng + + + + WelcomeViewStep + + + Welcome + Chào mừng + + + + about + + + <h1>%1</h1><br/> + <strong>%2<br/> + for %3</strong><br/><br/> + Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/> + Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/> + Thanks to <a href='https://calamares.io/team/'>the Calamares team</a> + and the <a href='https://www.transifex.com/calamares/calamares/'>Calamares + translators team</a>.<br/><br/> + <a href='https://calamares.io/'>Calamares</a> + development is sponsored by <br/> + <a href='http://www.blue-systems.com/'>Blue Systems</a> - + Liberating Software. + <h1>%1</h1><br/> + <strong>%2<br/> + cho %3</strong><br/><br/> + Bản quyền 2014-2017 bởi Teo Mrnjavac &lt;teo@kde.org&gt;<br/> + Bản quyền 2017-2020 bởi Adriaan de Groot &lt;groot@kde.org&gt;<br/> + Cám ơn <a href='https://calamares.io/team/'>đội ngũ Calamares</a> + và <a href='https://www.transifex.com/calamares/calamares/'>các dịch giả Calamares</a>.<br/><br/> + <a href='https://calamares.io/'>Calamares</a> + được tài trợ bởi <br/> + <a href='http://www.blue-systems.com/'>Blue Systems</a> - + Liberating Software. + + + + Back + Quay lại + + + + i18n + + + <h1>Languages</h1> </br> + The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>. + <h1>Ngôn ngữ</h1> </br> + Cài đặt ngôn ngữ hệ thống ảnh hưởng đến ngôn ngữ và bộ ký tự cho một số thành phần giao diện người dùng dòng lệnh. Cài đặt hiện tại là <strong>%1</strong>. + + + + <h1>Locales</h1> </br> + The system locale setting affects the numbers and dates format. The current setting is <strong>%1</strong>. + <h1>Địa phương</h1> </br> + Cài đặt ngôn ngữ hệ thống ảnh hưởng đến số và định dạng ngày tháng. Cài đặt hiện tại là <strong>%1</strong>. + + + + Back + Trở lại + + + + keyboardq + + + Keyboard Model + Mẫu bàn phím + + + + Layouts + Bố cục + + + + Keyboard Layout + Bố cục bàn phím + + + + Click your preferred keyboard model to select layout and variant, or use the default one based on the detected hardware. + Nhấp vào kiểu bàn phím ưa thích của bạn để chọn bố cục và biến thể hoặc sử dụng kiểu mặc định dựa trên phần cứng được phát hiện. + + + + Models + Mẫu + + + + Variants + Các biến thể + + + + Keyboard Variant + Các biến thể bàn phím + + + + Test your keyboard + Thử bàn phím + + + + localeq + + + Change + Đổi + + + + notesqml + + + <h3>%1</h3> + <p>These are example release notes.</p> + <h3>%1</h3> + <p>Đây là ghi chú phát hành mẫu.</p> + + + + release_notes + + + <h3>%1</h3> + <p>This an example QML file, showing options in RichText with Flickable content.</p> + + <p>QML with RichText can use HTML tags, Flickable content is useful for touchscreens.</p> + + <p><b>This is bold text</b></p> + <p><i>This is italic text</i></p> + <p><u>This is underlined text</u></p> + <p><center>This text will be center-aligned.</center></p> + <p><s>This is strikethrough</s></p> + + <p>Code example: + <code>ls -l /home</code></p> + + <p><b>Lists:</b></p> + <ul> + <li>Intel CPU systems</li> + <li>AMD CPU systems</li> + </ul> + + <p>The vertical scrollbar is adjustable, current width set to 10.</p> + <h3>%1</h3> + <p>Đây là một tệp QML mẫu, hiển thị các tùy chọn trong RichText với nội dung Flickable..</p> + + <p>QML với RichText có thể sử dụng thẻ HTML, nội dung Flickable hữu ích cho màn hình cảm ứng.</p> + + <p><b>Đây là văn bản in đậm</b></p> + <p><i>Đây là văn bản in nghiêng</i></p> + <p><u>Đây là văn bản được gạch chân</u></p> + <p><center>Văn bản này sẽ được căn giữa.</center></p> + <p><s>Đây là đường gạch ngang</s></p> + + <p>Ví dụ về mã: + <code>ls -l /home</code></p> + + <p><b>Danh sách:</b></p> + <ul> + <li>Hệ thống Intel CPU</li> + <li>Hệ thống AMD CPU</li> + </ul> + + <p>Thanh cuộn dọc có thể điều chỉnh được, chiều rộng hiện tại được đặt thành 10.</p> + + + + Back + Quay lại + + + + usersq + + + Pick your user name and credentials to login and perform admin tasks + Chọn tên bạn và chứng chỉ để đăng nhập và thực hiện các tác vụ quản trị + + + + What is your name? + Hãy cho Vigo biết tên đầy đủ của bạn? + + + + Your Full Name + Tên đầy đủ + + + + What name do you want to use to log in? + Bạn muốn dùng tên nào để đăng nhập máy tính? + + + + Login Name + Tên đăng nhập + + + + If more than one person will use this computer, you can create multiple accounts after installation. + Tạo nhiều tài khoản sau khi cài đặt nếu có nhiều người dùng chung. + + + + What is the name of this computer? + Tên của máy tính này là? + + + + Computer Name + Tên máy tính + + + + This name will be used if you make the computer visible to others on a network. + Tên này sẽ hiển thị khi bạn kết nối vào một mạng. + + + + Choose a password to keep your account safe. + Chọn mật khẩu để giữ máy tính an toàn. + + + + Password + Mật khẩu + + + + Repeat Password + Lặp lại mật khẩu + + + + Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals. + Nhập lại mật khẩu hai lần để kiểm tra. Một mật khẩu tốt phải có ít nhất 8 ký tự và bao gồm chữ, số, ký hiệu đặc biệt. Nên được thay đổi thường xuyên. + + + + Validate passwords quality + Xác thực chất lượng mật khẩu + + + + When this box is checked, password-strength checking is done and you will not be able to use a weak password. + Khi tích chọn, bạn có thể chọn mật khẩu yếu. + + + + Log in automatically without asking for the password + Tự động đăng nhập không hỏi mật khẩu + + + + Reuse user password as root password + Dùng lại mật khẩu người dùng như mật khẩu quản trị + + + + Use the same password for the administrator account. + Dùng cùng một mật khẩu cho tài khoản quản trị. + + + + Choose a root password to keep your account safe. + Chọn mật khẩu quản trị để giữ máy tính an toàn. + + + + Root Password + Mật khẩu quản trị + + + + Repeat Root Password + Lặp lại mật khẩu quản trị + + + + Enter the same password twice, so that it can be checked for typing errors. + Nhập lại mật khẩu hai lần để kiểm tra. + + + + welcomeq + + + <h3>Welcome to the %1 <quote>%2</quote> installer</h3> + <p>This program will ask you some questions and set up %1 on your computer.</p> + <h3>Chào mừng đến với bộ cài đặt %1 <quote>%2</quote></h3> + <p>Chương trình sẽ hỏi bản vài câu hỏi và thiết lập %1 trên máy tính của bạn.</p> + + + + About + Giới thiệu + + + + Support + Hỗ trợ + + + + Known issues + Các vấn đề đã biết + + + + Release notes + Ghi chú phát hành + + + + Donate + Ủng hộ + + + diff --git a/lang/calamares_zh_TW.ts b/lang/calamares_zh_TW.ts index fe5918943..85a49ee98 100644 --- a/lang/calamares_zh_TW.ts +++ b/lang/calamares_zh_TW.ts @@ -617,17 +617,17 @@ The installer will quit and all changes will be lost. This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + 此儲存裝置上已有作業系統,但分割表 <strong>%1</strong> 與需要的 <strong>%2</strong> 不同。<br/> This storage device has one of its partitions <strong>mounted</strong>. - + 此裝置<strong>已掛載</strong>其中一個分割區。 This storage device is a part of an <strong>inactive RAID</strong> device. - + 此儲存裝置是<strong>非作用中 RAID</strong> 裝置的一部份。 diff --git a/lang/kb_en.ts b/lang/kb_en.ts new file mode 100644 index 000000000..08dc54905 --- /dev/null +++ b/lang/kb_en.ts @@ -0,0 +1,4621 @@ + + + + + kb_layouts + + + Afghani + kb_layouts + + + + + Albanian + kb_layouts + + + + + Amharic + kb_layouts + + + + + Arabic + kb_layouts + + + + + Arabic (Morocco) + kb_layouts + + + + + Arabic (Syria) + kb_layouts + + + + + Armenian + kb_layouts + + + + + Azerbaijani + kb_layouts + + + + + Bambara + kb_layouts + + + + + Bangla + kb_layouts + + + + + Belarusian + kb_layouts + + + + + Belgian + kb_layouts + + + + + Bosnian + kb_layouts + + + + + Braille + kb_layouts + + + + + Bulgarian + kb_layouts + + + + + Burmese + kb_layouts + + + + + Chinese + kb_layouts + + + + + Croatian + kb_layouts + + + + + Czech + kb_layouts + + + + + Danish + kb_layouts + + + + + Dhivehi + kb_layouts + + + + + Dutch + kb_layouts + + + + + Dzongkha + kb_layouts + + + + + English (Australian) + kb_layouts + + + + + English (Cameroon) + kb_layouts + + + + + English (Ghana) + kb_layouts + + + + + English (Nigeria) + kb_layouts + + + + + English (South Africa) + kb_layouts + + + + + English (UK) + kb_layouts + + + + + English (US) + kb_layouts + + + + + Esperanto + kb_layouts + + + + + Estonian + kb_layouts + + + + + Faroese + kb_layouts + + + + + Filipino + kb_layouts + + + + + Finnish + kb_layouts + + + + + French + kb_layouts + + + + + French (Canada) + kb_layouts + + + + + French (Democratic Republic of the Congo) + kb_layouts + + + + + French (Guinea) + kb_layouts + + + + + French (Togo) + kb_layouts + + + + + Georgian + kb_layouts + + + + + German + kb_layouts + + + + + German (Austria) + kb_layouts + + + + + German (Switzerland) + kb_layouts + + + + + Greek + kb_layouts + + + + + Hebrew + kb_layouts + + + + + Hungarian + kb_layouts + + + + + Icelandic + kb_layouts + + + + + Indian + kb_layouts + + + + + Indonesian (Arab Melayu, phonetic) + kb_layouts + + + + + Indonesian (Javanese) + kb_layouts + + + + + Iraqi + kb_layouts + + + + + Irish + kb_layouts + + + + + Italian + kb_layouts + + + + + Japanese + kb_layouts + + + + + Japanese (PC-98) + kb_layouts + + + + + Kabylian (azerty layout, no dead keys) + kb_layouts + + + + + Kazakh + kb_layouts + + + + + Khmer (Cambodia) + kb_layouts + + + + + Korean + kb_layouts + + + + + Kyrgyz + kb_layouts + + + + + Lao + kb_layouts + + + + + Latvian + kb_layouts + + + + + Lithuanian + kb_layouts + + + + + Macedonian + kb_layouts + + + + + Malay (Jawi, Arabic Keyboard) + kb_layouts + + + + + Maltese + kb_layouts + + + + + Maori + kb_layouts + + + + + Moldavian + kb_layouts + + + + + Mongolian + kb_layouts + + + + + Montenegrin + kb_layouts + + + + + Nepali + kb_layouts + + + + + Norwegian + kb_layouts + + + + + Persian + kb_layouts + + + + + Polish + kb_layouts + + + + + Portuguese + kb_layouts + + + + + Portuguese (Brazil) + kb_layouts + + + + + Romanian + kb_layouts + + + + + Russian + kb_layouts + + + + + Serbian + kb_layouts + + + + + Sinhala (phonetic) + kb_layouts + + + + + Slovak + kb_layouts + + + + + Slovenian + kb_layouts + + + + + Spanish + kb_layouts + + + + + Spanish (Latin American) + kb_layouts + + + + + Swahili (Kenya) + kb_layouts + + + + + Swahili (Tanzania) + kb_layouts + + + + + Swedish + kb_layouts + + + + + Taiwanese + kb_layouts + + + + + Tajik + kb_layouts + + + + + Thai + kb_layouts + + + + + Tswana + kb_layouts + + + + + Turkish + kb_layouts + + + + + Turkmen + kb_layouts + + + + + Ukrainian + kb_layouts + + + + + Urdu (Pakistan) + kb_layouts + + + + + Uzbek + kb_layouts + + + + + Vietnamese + kb_layouts + + + + + Wolof + kb_layouts + + + + + kb_models + + + A4Tech KB-21 + kb_models + + + + + A4Tech KBS-8 + kb_models + + + + + A4Tech Wireless Desktop RFKB-23 + kb_models + + + + + Acer AirKey V + kb_models + + + + + Acer C300 + kb_models + + + + + Acer Ferrari 4000 + kb_models + + + + + Acer laptop + kb_models + + + + + Advance Scorpius KI + kb_models + + + + + Apple + kb_models + + + + + Apple Aluminium (ANSI) + kb_models + + + + + Apple Aluminium (ISO) + kb_models + + + + + Apple Aluminium (JIS) + kb_models + + + + + Apple laptop + kb_models + + + + + Asus laptop + kb_models + + + + + Azona RF2300 wireless Internet + kb_models + + + + + BTC 5090 + kb_models + + + + + BTC 5113RF Multimedia + kb_models + + + + + BTC 5126T + kb_models + + + + + BTC 6301URF + kb_models + + + + + BTC 9000 + kb_models + + + + + BTC 9000A + kb_models + + + + + BTC 9001AH + kb_models + + + + + BTC 9019U + kb_models + + + + + BTC 9116U Mini Wireless Internet and Gaming + kb_models + + + + + BenQ X-Touch + kb_models + + + + + BenQ X-Touch 730 + kb_models + + + + + BenQ X-Touch 800 + kb_models + + + + + Brother Internet + kb_models + + + + + Cherry B.UNLIMITED + kb_models + + + + + Cherry Blue Line CyBo@rd + kb_models + + + + + Cherry Blue Line CyBo@rd (alt.) + kb_models + + + + + Cherry CyBo@rd USB-Hub + kb_models + + + + + Cherry CyMotion Expert + kb_models + + + + + Cherry CyMotion Master Linux + kb_models + + + + + Cherry CyMotion Master XPress + kb_models + + + + + Chicony Internet + kb_models + + + + + Chicony KB-9885 + kb_models + + + + + Chicony KU-0108 + kb_models + + + + + Chicony KU-0420 + kb_models + + + + + Chromebook + kb_models + + + + + Classmate PC + kb_models + + + + + Compaq Armada laptop + kb_models + + + + + Compaq Easy Access + kb_models + + + + + Compaq Internet (13 keys) + kb_models + + + + + Compaq Internet (18 keys) + kb_models + + + + + Compaq Internet (7 keys) + kb_models + + + + + Compaq Presario laptop + kb_models + + + + + Compaq iPaq + kb_models + + + + + Creative Desktop Wireless 7000 + kb_models + + + + + DTK2000 + kb_models + + + + + Dell + kb_models + + + + + Dell 101-key PC + kb_models + + + + + Dell Inspiron 6000/8000 laptop + kb_models + + + + + Dell Latitude laptop + kb_models + + + + + Dell Precision M laptop + kb_models + + + + + Dell Precision M65 laptop + kb_models + + + + + Dell SK-8125 + kb_models + + + + + Dell SK-8135 + kb_models + + + + + Dell USB Multimedia + kb_models + + + + + Dexxa Wireless Desktop + kb_models + + + + + Diamond 9801/9802 + kb_models + + + + + Ennyah DKB-1008 + kb_models + + + + + Everex STEPnote + kb_models + + + + + FL90 + kb_models + + + + + Fujitsu-Siemens Amilo laptop + kb_models + + + + + Generic 101-key PC + kb_models + + + + + Generic 102-key PC + kb_models + + + + + Generic 104-key PC + kb_models + + + + + Generic 104-key PC with L-shaped Enter key + kb_models + + + + + Generic 105-key PC + kb_models + + + + + Generic 86-key PC + kb_models + + + + + Genius Comfy KB-12e + kb_models + + + + + Genius Comfy KB-16M/Multimedia KWD-910 + kb_models + + + + + Genius Comfy KB-21e-Scroll + kb_models + + + + + Genius KB-19e NB + kb_models + + + + + Genius KKB-2050HS + kb_models + + + + + Gyration + kb_models + + + + + Happy Hacking + kb_models + + + + + Happy Hacking for Mac + kb_models + + + + + Hewlett-Packard Internet + kb_models + + + + + Hewlett-Packard Mini 110 laptop + kb_models + + + + + Hewlett-Packard NEC SK-2500 Multimedia + kb_models + + + + + Hewlett-Packard Omnibook 500 + kb_models + + + + + Hewlett-Packard Omnibook 500 FA + kb_models + + + + + Hewlett-Packard Omnibook 6000/6100 + kb_models + + + + + Hewlett-Packard Omnibook XE3 GC + kb_models + + + + + Hewlett-Packard Omnibook XE3 GF + kb_models + + + + + Hewlett-Packard Omnibook XT1000 + kb_models + + + + + Hewlett-Packard Pavilion ZT1100 + kb_models + + + + + Hewlett-Packard Pavilion dv5 + kb_models + + + + + Hewlett-Packard nx9020 + kb_models + + + + + Honeywell Euroboard + kb_models + + + + + IBM Rapid Access + kb_models + + + + + IBM Rapid Access II + kb_models + + + + + IBM Space Saver + kb_models + + + + + IBM ThinkPad 560Z/600/600E/A22E + kb_models + + + + + IBM ThinkPad R60/T60/R61/T61 + kb_models + + + + + IBM ThinkPad Z60m/Z60t/Z61m/Z61t + kb_models + + + + + Keytronic FlexPro + kb_models + + + + + Kinesis + kb_models + + + + + Logitech + kb_models + + + + + Logitech Access + kb_models + + + + + Logitech Cordless Desktop + kb_models + + + + + Logitech Cordless Desktop (alt.) + kb_models + + + + + Logitech Cordless Desktop EX110 + kb_models + + + + + Logitech Cordless Desktop LX-300 + kb_models + + + + + Logitech Cordless Desktop Navigator + kb_models + + + + + Logitech Cordless Desktop Optical + kb_models + + + + + Logitech Cordless Desktop Pro (2nd alt.) + kb_models + + + + + Logitech Cordless Desktop iTouch + kb_models + + + + + Logitech Cordless Freedom/Desktop Navigator + kb_models + + + + + Logitech G15 extra keys via G15daemon + kb_models + + + + + Logitech Internet + kb_models + + + + + Logitech Internet 350 + kb_models + + + + + Logitech Internet Navigator + kb_models + + + + + Logitech Ultra-X + kb_models + + + + + Logitech Ultra-X Cordless Media Desktop + kb_models + + + + + Logitech diNovo + kb_models + + + + + Logitech diNovo Edge + kb_models + + + + + Logitech iTouch + kb_models + + + + + Logitech iTouch Cordless Y-RB6 + kb_models + + + + + Logitech iTouch Internet Navigator SE + kb_models + + + + + Logitech iTouch Internet Navigator SE USB + kb_models + + + + + MacBook/MacBook Pro + kb_models + + + + + MacBook/MacBook Pro (intl.) + kb_models + + + + + Macintosh + kb_models + + + + + Macintosh Old + kb_models + + + + + Memorex MX1998 + kb_models + + + + + Memorex MX2500 EZ-Access + kb_models + + + + + Memorex MX2750 + kb_models + + + + + Microsoft Comfort Curve 2000 + kb_models + + + + + Microsoft Internet + kb_models + + + + + Microsoft Internet Pro (Swedish) + kb_models + + + + + Microsoft Natural + kb_models + + + + + Microsoft Natural Elite + kb_models + + + + + Microsoft Natural Ergonomic 4000 + kb_models + + + + + Microsoft Natural Pro OEM + kb_models + + + + + Microsoft Natural Pro USB/Internet Pro + kb_models + + + + + Microsoft Natural Pro/Internet Pro + kb_models + + + + + Microsoft Natural Wireless Ergonomic 7000 + kb_models + + + + + Microsoft Office Keyboard + kb_models + + + + + Microsoft Surface + kb_models + + + + + Microsoft Wireless Multimedia 1.0A + kb_models + + + + + NEC SK-1300 + kb_models + + + + + NEC SK-2500 + kb_models + + + + + NEC SK-6200 + kb_models + + + + + NEC SK-7100 + kb_models + + + + + Northgate OmniKey 101 + kb_models + + + + + OLPC + kb_models + + + + + Ortek Multimedia/Internet MCK-800 + kb_models + + + + + PC-98 + kb_models + + + + + Propeller Voyager KTEZ-1000 + kb_models + + + + + QTronix Scorpius 98N+ + kb_models + + + + + SVEN Ergonomic 2500 + kb_models + + + + + SVEN Slim 303 + kb_models + + + + + Samsung SDM 4500P + kb_models + + + + + Samsung SDM 4510P + kb_models + + + + + Sanwa Supply SKB-KG3 + kb_models + + + + + Silvercrest Multimedia Wireless + kb_models + + + + + SteelSeries Apex 300 (Apex RAW) + kb_models + + + + + Sun Type 6 (Japanese) + kb_models + + + + + Sun Type 6 USB (Japanese) + kb_models + + + + + Sun Type 6 USB (Unix) + kb_models + + + + + Sun Type 6/7 USB + kb_models + + + + + Sun Type 6/7 USB (European) + kb_models + + + + + Sun Type 7 USB + kb_models + + + + + Sun Type 7 USB (European) + kb_models + + + + + Sun Type 7 USB (Japanese)/Japanese 106-key + kb_models + + + + + Sun Type 7 USB (Unix) + kb_models + + + + + Super Power Multimedia + kb_models + + + + + Symplon PaceBook tablet + kb_models + + + + + Targa Visionary 811 + kb_models + + + + + Toshiba Satellite S3000 + kb_models + + + + + Truly Ergonomic 227 + kb_models + + + + + Truly Ergonomic 229 + kb_models + + + + + Truly Ergonomic Computer Keyboard Model 227 (Wide Alt keys) + kb_models + + + + + Truly Ergonomic Computer Keyboard Model 229 (Standard sized Alt keys, additional Super and Menu key) + kb_models + + + + + Trust Direct Access + kb_models + + + + + Trust Slimline + kb_models + + + + + Trust Wireless Classic + kb_models + + + + + TypeMatrix EZ-Reach 2020 + kb_models + + + + + TypeMatrix EZ-Reach 2030 PS2 + kb_models + + + + + TypeMatrix EZ-Reach 2030 USB + kb_models + + + + + TypeMatrix EZ-Reach 2030 USB (102/105:EU mode) + kb_models + + + + + TypeMatrix EZ-Reach 2030 USB (106:JP mode) + kb_models + + + + + Unitek KB-1925 + kb_models + + + + + ViewSonic KU-306 Internet + kb_models + + + + + Winbook Model XP5 + kb_models + + + + + Yahoo! Internet + kb_models + + + + + eMachines m6800 laptop + kb_models + + + + + kb_variants + + + Akan + kb_variants + + + + + Albanian (Plisi) + kb_variants + + + + + Albanian (Veqilharxhi) + kb_variants + + + + + Arabic (AZERTY) + kb_variants + + + + + Arabic (AZERTY, Eastern Arabic numerals) + kb_variants + + + + + Arabic (Algeria) + kb_variants + + + + + Arabic (Buckwalter) + kb_variants + + + + + Arabic (Eastern Arabic numerals) + kb_variants + + + + + Arabic (Macintosh) + kb_variants + + + + + Arabic (OLPC) + kb_variants + + + + + Arabic (Pakistan) + kb_variants + + + + + Arabic (QWERTY) + kb_variants + + + + + Arabic (QWERTY, Eastern Arabic numerals) + kb_variants + + + + + Armenian (alt. eastern) + kb_variants + + + + + Armenian (alt. phonetic) + kb_variants + + + + + Armenian (eastern) + kb_variants + + + + + Armenian (phonetic) + kb_variants + + + + + Armenian (western) + kb_variants + + + + + Asturian (Spain, with bottom-dot H and L) + kb_variants + + + + + Avatime + kb_variants + + + + + Azerbaijani (Cyrillic) + kb_variants + + + + + Bangla (India) + kb_variants + + + + + Bangla (India, Baishakhi Inscript) + kb_variants + + + + + Bangla (India, Baishakhi) + kb_variants + + + + + Bangla (India, Bornona) + kb_variants + + + + + Bangla (India, Gitanjali) + kb_variants + + + + + Bangla (India, Probhat) + kb_variants + + + + + Bangla (Probhat) + kb_variants + + + + + Bashkirian + kb_variants + + + + + Belarusian (Latin) + kb_variants + + + + + Belarusian (intl.) + kb_variants + + + + + Belarusian (legacy) + kb_variants + + + + + Belgian (ISO, alt.) + kb_variants + + + + + Belgian (Latin-9 only, alt.) + kb_variants + + + + + Belgian (Sun dead keys) + kb_variants + + + + + Belgian (Sun dead keys, alt.) + kb_variants + + + + + Belgian (Wang 724 AZERTY) + kb_variants + + + + + Belgian (alt.) + kb_variants + + + + + Belgian (no dead keys) + kb_variants + + + + + Berber (Morocco, Tifinagh alt.) + kb_variants + + + + + Berber (Morocco, Tifinagh extended phonetic) + kb_variants + + + + + Berber (Morocco, Tifinagh extended) + kb_variants + + + + + Berber (Morocco, Tifinagh phonetic) + kb_variants + + + + + Berber (Morocco, Tifinagh phonetic, alt.) + kb_variants + + + + + Berber (Morocco, Tifinagh) + kb_variants + + + + + Bosnian (US) + kb_variants + + + + + Bosnian (US, with Bosnian digraphs) + kb_variants + + + + + Bosnian (with Bosnian digraphs) + kb_variants + + + + + Bosnian (with guillemets) + kb_variants + + + + + Braille (left-handed inverted thumb) + kb_variants + + + + + Braille (left-handed) + kb_variants + + + + + Braille (right-handed inverted thumb) + kb_variants + + + + + Braille (right-handed) + kb_variants + + + + + Bulgarian (enhanced) + kb_variants + + + + + Bulgarian (new phonetic) + kb_variants + + + + + Bulgarian (traditional phonetic) + kb_variants + + + + + Burmese Zawgyi + kb_variants + + + + + Cameroon (AZERTY, intl.) + kb_variants + + + + + Cameroon (Dvorak, intl.) + kb_variants + + + + + Cameroon Multilingual (QWERTY, intl.) + kb_variants + + + + + Canadian (intl.) + kb_variants + + + + + Canadian (intl., 1st part) + kb_variants + + + + + Canadian (intl., 2nd part) + kb_variants + + + + + Catalan (Spain, with middle-dot L) + kb_variants + + + + + Cherokee + kb_variants + + + + + Chuvash + kb_variants + + + + + Chuvash (Latin) + kb_variants + + + + + CloGaelach + kb_variants + + + + + Crimean Tatar (Turkish Alt-Q) + kb_variants + + + + + Crimean Tatar (Turkish F) + kb_variants + + + + + Crimean Tatar (Turkish Q) + kb_variants + + + + + Croatian (US) + kb_variants + + + + + Croatian (US, with Croatian digraphs) + kb_variants + + + + + Croatian (with Croatian digraphs) + kb_variants + + + + + Croatian (with guillemets) + kb_variants + + + + + Czech (QWERTY) + kb_variants + + + + + Czech (QWERTY, Macintosh) + kb_variants + + + + + Czech (QWERTY, extended backslash) + kb_variants + + + + + Czech (UCW, only accented letters) + kb_variants + + + + + Czech (US, Dvorak, UCW support) + kb_variants + + + + + Czech (with &lt;|&gt; key) + kb_variants + + + + + Danish (Dvorak) + kb_variants + + + + + Danish (Macintosh) + kb_variants + + + + + Danish (Macintosh, no dead keys) + kb_variants + + + + + Danish (Windows) + kb_variants + + + + + Danish (no dead keys) + kb_variants + + + + + Default + kb_variants + + + + + Dutch (Macintosh) + kb_variants + + + + + Dutch (Sun dead keys) + kb_variants + + + + + Dutch (standard) + kb_variants + + + + + English (Canada) + kb_variants + + + + + English (Colemak) + kb_variants + + + + + English (Dvorak) + kb_variants + + + + + English (Dvorak, alt. intl.) + kb_variants + + + + + English (Dvorak, intl., with dead keys) + kb_variants + + + + + English (Dvorak, left-handed) + kb_variants + + + + + English (Dvorak, right-handed) + kb_variants + + + + + English (Ghana, GILLBT) + kb_variants + + + + + English (Ghana, multilingual) + kb_variants + + + + + English (India, with rupee) + kb_variants + + + + + English (Macintosh) + kb_variants + + + + + English (Mali, US, Macintosh) + kb_variants + + + + + English (Mali, US, intl.) + kb_variants + + + + + English (Norman) + kb_variants + + + + + English (UK, Colemak) + kb_variants + + + + + English (UK, Dvorak) + kb_variants + + + + + English (UK, Dvorak, with UK punctuation) + kb_variants + + + + + English (UK, Macintosh) + kb_variants + + + + + English (UK, Macintosh, intl.) + kb_variants + + + + + English (UK, extended, Windows) + kb_variants + + + + + English (UK, intl., with dead keys) + kb_variants + + + + + English (US, Symbolic) + kb_variants + + + + + English (US, alt. intl.) + kb_variants + + + + + English (US, euro on 5) + kb_variants + + + + + English (US, intl., with dead keys) + kb_variants + + + + + English (Workman) + kb_variants + + + + + English (Workman, intl., with dead keys) + kb_variants + + + + + English (classic Dvorak) + kb_variants + + + + + English (intl., with AltGr dead keys) + kb_variants + + + + + English (programmer Dvorak) + kb_variants + + + + + English (the divide/multiply toggle the layout) + kb_variants + + + + + Esperanto (Brazil, Nativo) + kb_variants + + + + + Esperanto (Portugal, Nativo) + kb_variants + + + + + Esperanto (legacy) + kb_variants + + + + + Estonian (Dvorak) + kb_variants + + + + + Estonian (US) + kb_variants + + + + + Estonian (no dead keys) + kb_variants + + + + + Ewe + kb_variants + + + + + Faroese (no dead keys) + kb_variants + + + + + Filipino (Capewell-Dvorak, Baybayin) + kb_variants + + + + + Filipino (Capewell-Dvorak, Latin) + kb_variants + + + + + Filipino (Capewell-QWERF 2006, Baybayin) + kb_variants + + + + + Filipino (Capewell-QWERF 2006, Latin) + kb_variants + + + + + Filipino (Colemak, Baybayin) + kb_variants + + + + + Filipino (Colemak, Latin) + kb_variants + + + + + Filipino (Dvorak, Baybayin) + kb_variants + + + + + Filipino (Dvorak, Latin) + kb_variants + + + + + Filipino (QWERTY, Baybayin) + kb_variants + + + + + Finnish (Macintosh) + kb_variants + + + + + Finnish (Windows) + kb_variants + + + + + Finnish (classic) + kb_variants + + + + + Finnish (classic, no dead keys) + kb_variants + + + + + French (AZERTY) + kb_variants + + + + + French (AZERTY, AFNOR) + kb_variants + + + + + French (BEPO) + kb_variants + + + + + French (BEPO, AFNOR) + kb_variants + + + + + French (BEPO, Latin-9 only) + kb_variants + + + + + French (Breton) + kb_variants + + + + + French (Cameroon) + kb_variants + + + + + French (Canada, Dvorak) + kb_variants + + + + + French (Canada, legacy) + kb_variants + + + + + French (Dvorak) + kb_variants + + + + + French (Macintosh) + kb_variants + + + + + French (Mali, alt.) + kb_variants + + + + + French (Morocco) + kb_variants + + + + + French (Sun dead keys) + kb_variants + + + + + French (Switzerland) + kb_variants + + + + + French (Switzerland, Macintosh) + kb_variants + + + + + French (Switzerland, Sun dead keys) + kb_variants + + + + + French (Switzerland, no dead keys) + kb_variants + + + + + French (US) + kb_variants + + + + + French (alt.) + kb_variants + + + + + French (alt., Latin-9 only) + kb_variants + + + + + French (alt., Sun dead keys) + kb_variants + + + + + French (alt., no dead keys) + kb_variants + + + + + French (legacy, alt.) + kb_variants + + + + + French (legacy, alt., Sun dead keys) + kb_variants + + + + + French (legacy, alt., no dead keys) + kb_variants + + + + + French (no dead keys) + kb_variants + + + + + Friulian (Italy) + kb_variants + + + + + Fula + kb_variants + + + + + Ga + kb_variants + + + + + Georgian (France, AZERTY Tskapo) + kb_variants + + + + + Georgian (Italy) + kb_variants + + + + + Georgian (MESS) + kb_variants + + + + + Georgian (ergonomic) + kb_variants + + + + + German (Austria, Macintosh) + kb_variants + + + + + German (Austria, Sun dead keys) + kb_variants + + + + + German (Austria, no dead keys) + kb_variants + + + + + German (Dvorak) + kb_variants + + + + + German (E1) + kb_variants + + + + + German (E2) + kb_variants + + + + + German (Macintosh) + kb_variants + + + + + German (Macintosh, no dead keys) + kb_variants + + + + + German (Neo 2) + kb_variants + + + + + German (QWERTY) + kb_variants + + + + + German (Sun dead keys) + kb_variants + + + + + German (Switzerland, Macintosh) + kb_variants + + + + + German (Switzerland, Sun dead keys) + kb_variants + + + + + German (Switzerland, legacy) + kb_variants + + + + + German (Switzerland, no dead keys) + kb_variants + + + + + German (T3) + kb_variants + + + + + German (US) + kb_variants + + + + + German (dead acute) + kb_variants + + + + + German (dead grave acute) + kb_variants + + + + + German (dead tilde) + kb_variants + + + + + German (no dead keys) + kb_variants + + + + + Greek (extended) + kb_variants + + + + + Greek (no dead keys) + kb_variants + + + + + Greek (polytonic) + kb_variants + + + + + Greek (simple) + kb_variants + + + + + Gujarati + kb_variants + + + + + Hanyu Pinyin (with AltGr dead keys) + kb_variants + + + + + Hausa (Ghana) + kb_variants + + + + + Hausa (Nigeria) + kb_variants + + + + + Hawaiian + kb_variants + + + + + Hebrew (Biblical, Tiro) + kb_variants + + + + + Hebrew (lyx) + kb_variants + + + + + Hebrew (phonetic) + kb_variants + + + + + Hindi (Bolnagri) + kb_variants + + + + + Hindi (KaGaPa, phonetic) + kb_variants + + + + + Hindi (Wx) + kb_variants + + + + + Hungarian (QWERTY) + kb_variants + + + + + Hungarian (QWERTY, 101-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 101-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTY, 101-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 101-key, dot, no dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, dot, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, dot, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, dot, no dead keys) + kb_variants + + + + + Hungarian (no dead keys) + kb_variants + + + + + Hungarian (standard) + kb_variants + + + + + Icelandic (Dvorak) + kb_variants + + + + + Icelandic (Macintosh) + kb_variants + + + + + Icelandic (Macintosh, legacy) + kb_variants + + + + + Icelandic (Sun dead keys) + kb_variants + + + + + Icelandic (no dead keys) + kb_variants + + + + + Igbo + kb_variants + + + + + Indic (phonetic, IPA) + kb_variants + + + + + Indonesian (Arab Melayu, extended phonetic) + kb_variants + + + + + Inuktitut + kb_variants + + + + + Irish (UnicodeExpert) + kb_variants + + + + + Italian (IBM 142) + kb_variants + + + + + Italian (Macintosh) + kb_variants + + + + + Italian (US) + kb_variants + + + + + Italian (Windows) + kb_variants + + + + + Italian (intl., with dead keys) + kb_variants + + + + + Italian (no dead keys) + kb_variants + + + + + Japanese (Dvorak) + kb_variants + + + + + Japanese (Kana 86) + kb_variants + + + + + Japanese (Kana) + kb_variants + + + + + Japanese (Macintosh) + kb_variants + + + + + Japanese (OADG 109A) + kb_variants + + + + + Kabylian (Algeria, Tifinagh) + kb_variants + + + + + Kabylian (azerty layout, with dead keys) + kb_variants + + + + + Kabylian (qwerty-gb layout, with dead keys) + kb_variants + + + + + Kabylian (qwerty-us layout, with dead keys) + kb_variants + + + + + Kalmyk + kb_variants + + + + + Kannada + kb_variants + + + + + Kannada (KaGaPa, phonetic) + kb_variants + + + + + Kashubian + kb_variants + + + + + Kazakh (Latin) + kb_variants + + + + + Kazakh (extended) + kb_variants + + + + + Kazakh (with Russian) + kb_variants + + + + + Kikuyu + kb_variants + + + + + Komi + kb_variants + + + + + Korean (101/104-key compatible) + kb_variants + + + + + Kurdish (Iran, Arabic-Latin) + kb_variants + + + + + Kurdish (Iran, F) + kb_variants + + + + + Kurdish (Iran, Latin Alt-Q) + kb_variants + + + + + Kurdish (Iran, Latin Q) + kb_variants + + + + + Kurdish (Iraq, Arabic-Latin) + kb_variants + + + + + Kurdish (Iraq, F) + kb_variants + + + + + Kurdish (Iraq, Latin Alt-Q) + kb_variants + + + + + Kurdish (Iraq, Latin Q) + kb_variants + + + + + Kurdish (Syria, F) + kb_variants + + + + + Kurdish (Syria, Latin Alt-Q) + kb_variants + + + + + Kurdish (Syria, Latin Q) + kb_variants + + + + + Kurdish (Turkey, F) + kb_variants + + + + + Kurdish (Turkey, Latin Alt-Q) + kb_variants + + + + + Kurdish (Turkey, Latin Q) + kb_variants + + + + + Kyrgyz (phonetic) + kb_variants + + + + + Lao (STEA) + kb_variants + + + + + Latvian (F) + kb_variants + + + + + Latvian (adapted) + kb_variants + + + + + Latvian (apostrophe) + kb_variants + + + + + Latvian (ergonomic, ŪGJRMV) + kb_variants + + + + + Latvian (modern) + kb_variants + + + + + Latvian (tilde) + kb_variants + + + + + Lithuanian (IBM LST 1205-92) + kb_variants + + + + + Lithuanian (LEKP) + kb_variants + + + + + Lithuanian (LEKPa) + kb_variants + + + + + Lithuanian (US) + kb_variants + + + + + Lithuanian (standard) + kb_variants + + + + + Lower Sorbian + kb_variants + + + + + Lower Sorbian (QWERTZ) + kb_variants + + + + + Macedonian (no dead keys) + kb_variants + + + + + Malay (Jawi, phonetic) + kb_variants + + + + + Malayalam + kb_variants + + + + + Malayalam (Lalitha) + kb_variants + + + + + Malayalam (enhanced Inscript, with rupee) + kb_variants + + + + + Maltese (UK, with AltGr overrides) + kb_variants + + + + + Maltese (US layout with AltGr overrides) + kb_variants + + + + + Maltese (US) + kb_variants + + + + + Manipuri (Eeyek) + kb_variants + + + + + Marathi (KaGaPa, phonetic) + kb_variants + + + + + Marathi (enhanced Inscript) + kb_variants + + + + + Mari + kb_variants + + + + + Mmuock + kb_variants + + + + + Moldavian (Gagauz) + kb_variants + + + + + Mongolian (Bichig) + kb_variants + + + + + Mongolian (Galik) + kb_variants + + + + + Mongolian (Manchu Galik) + kb_variants + + + + + Mongolian (Manchu) + kb_variants + + + + + Mongolian (Todo Galik) + kb_variants + + + + + Mongolian (Todo) + kb_variants + + + + + Mongolian (Xibe) + kb_variants + + + + + Montenegrin (Cyrillic) + kb_variants + + + + + Montenegrin (Cyrillic, ZE and ZHE swapped) + kb_variants + + + + + Montenegrin (Cyrillic, with guillemets) + kb_variants + + + + + Montenegrin (Latin, QWERTY) + kb_variants + + + + + Montenegrin (Latin, Unicode) + kb_variants + + + + + Montenegrin (Latin, Unicode, QWERTY) + kb_variants + + + + + Montenegrin (Latin, with guillemets) + kb_variants + + + + + Northern Saami (Finland) + kb_variants + + + + + Northern Saami (Norway) + kb_variants + + + + + Northern Saami (Norway, no dead keys) + kb_variants + + + + + Northern Saami (Sweden) + kb_variants + + + + + Norwegian (Colemak) + kb_variants + + + + + Norwegian (Dvorak) + kb_variants + + + + + Norwegian (Macintosh) + kb_variants + + + + + Norwegian (Macintosh, no dead keys) + kb_variants + + + + + Norwegian (Windows) + kb_variants + + + + + Norwegian (no dead keys) + kb_variants + + + + + Occitan + kb_variants + + + + + Ogham + kb_variants + + + + + Ogham (IS434) + kb_variants + + + + + Ol Chiki + kb_variants + + + + + Oriya + kb_variants + + + + + Ossetian (Georgia) + kb_variants + + + + + Ossetian (Windows) + kb_variants + + + + + Ossetian (legacy) + kb_variants + + + + + Pannonian Rusyn + kb_variants + + + + + Pashto + kb_variants + + + + + Pashto (Afghanistan, OLPC) + kb_variants + + + + + Persian (Afghanistan, Dari OLPC) + kb_variants + + + + + Persian (with Persian keypad) + kb_variants + + + + + Polish (British keyboard) + kb_variants + + + + + Polish (Dvorak) + kb_variants + + + + + Polish (Dvorak, with Polish quotes on key 1) + kb_variants + + + + + Polish (Dvorak, with Polish quotes on quotemark key) + kb_variants + + + + + Polish (QWERTZ) + kb_variants + + + + + Polish (legacy) + kb_variants + + + + + Polish (programmer Dvorak) + kb_variants + + + + + Portuguese (Brazil, Dvorak) + kb_variants + + + + + Portuguese (Brazil, IBM/Lenovo ThinkPad) + kb_variants + + + + + Portuguese (Brazil, Nativo for US keyboards) + kb_variants + + + + + Portuguese (Brazil, Nativo) + kb_variants + + + + + Portuguese (Brazil, no dead keys) + kb_variants + + + + + Portuguese (Macintosh) + kb_variants + + + + + Portuguese (Macintosh, Sun dead keys) + kb_variants + + + + + Portuguese (Macintosh, no dead keys) + kb_variants + + + + + Portuguese (Nativo for US keyboards) + kb_variants + + + + + Portuguese (Nativo) + kb_variants + + + + + Portuguese (Sun dead keys) + kb_variants + + + + + Portuguese (no dead keys) + kb_variants + + + + + Punjabi (Gurmukhi Jhelum) + kb_variants + + + + + Punjabi (Gurmukhi) + kb_variants + + + + + Romanian (Germany) + kb_variants + + + + + Romanian (Germany, no dead keys) + kb_variants + + + + + Romanian (Windows) + kb_variants + + + + + Romanian (cedilla) + kb_variants + + + + + Romanian (standard cedilla) + kb_variants + + + + + Romanian (standard) + kb_variants + + + + + Russian (Belarus) + kb_variants + + + + + Russian (Czech, phonetic) + kb_variants + + + + + Russian (DOS) + kb_variants + + + + + Russian (Georgia) + kb_variants + + + + + Russian (Germany, phonetic) + kb_variants + + + + + Russian (Kazakhstan, with Kazakh) + kb_variants + + + + + Russian (Macintosh) + kb_variants + + + + + Russian (Poland, phonetic Dvorak) + kb_variants + + + + + Russian (Sweden, phonetic) + kb_variants + + + + + Russian (Sweden, phonetic, no dead keys) + kb_variants + + + + + Russian (US, phonetic) + kb_variants + + + + + Russian (Ukraine, standard RSTU) + kb_variants + + + + + Russian (legacy) + kb_variants + + + + + Russian (phonetic) + kb_variants + + + + + Russian (phonetic, AZERTY) + kb_variants + + + + + Russian (phonetic, Dvorak) + kb_variants + + + + + Russian (phonetic, French) + kb_variants + + + + + Russian (phonetic, Windows) + kb_variants + + + + + Russian (phonetic, YAZHERTY) + kb_variants + + + + + Russian (typewriter) + kb_variants + + + + + Russian (typewriter, legacy) + kb_variants + + + + + Saisiyat (Taiwan) + kb_variants + + + + + Samogitian + kb_variants + + + + + Sanskrit (KaGaPa, phonetic) + kb_variants + + + + + Serbian (Cyrillic, ZE and ZHE swapped) + kb_variants + + + + + Serbian (Cyrillic, with guillemets) + kb_variants + + + + + Serbian (Latin) + kb_variants + + + + + Serbian (Latin, QWERTY) + kb_variants + + + + + Serbian (Latin, Unicode) + kb_variants + + + + + Serbian (Latin, Unicode, QWERTY) + kb_variants + + + + + Serbian (Latin, with guillemets) + kb_variants + + + + + Serbian (Russia) + kb_variants + + + + + Serbo-Croatian (US) + kb_variants + + + + + Sicilian + kb_variants + + + + + Silesian + kb_variants + + + + + Sindhi + kb_variants + + + + + Sinhala (US) + kb_variants + + + + + Slovak (QWERTY) + kb_variants + + + + + Slovak (QWERTY, extended backslash) + kb_variants + + + + + Slovak (extended backslash) + kb_variants + + + + + Slovenian (US) + kb_variants + + + + + Slovenian (with guillemets) + kb_variants + + + + + Spanish (Dvorak) + kb_variants + + + + + Spanish (Latin American, Colemak for gaming) + kb_variants + + + + + Spanish (Latin American, Colemak) + kb_variants + + + + + Spanish (Latin American, Dvorak) + kb_variants + + + + + Spanish (Latin American, Sun dead keys) + kb_variants + + + + + Spanish (Latin American, dead tilde) + kb_variants + + + + + Spanish (Latin American, no dead keys) + kb_variants + + + + + Spanish (Macintosh) + kb_variants + + + + + Spanish (Sun dead keys) + kb_variants + + + + + Spanish (Windows) + kb_variants + + + + + Spanish (dead tilde) + kb_variants + + + + + Spanish (no dead keys) + kb_variants + + + + + Swedish (Dvorak) + kb_variants + + + + + Swedish (Dvorak, intl.) + kb_variants + + + + + Swedish (Macintosh) + kb_variants + + + + + Swedish (Svdvorak) + kb_variants + + + + + Swedish (US) + kb_variants + + + + + Swedish (no dead keys) + kb_variants + + + + + Swedish Sign Language + kb_variants + + + + + Syriac + kb_variants + + + + + Syriac (phonetic) + kb_variants + + + + + Taiwanese (indigenous) + kb_variants + + + + + Tajik (legacy) + kb_variants + + + + + Tamil (Inscript) + kb_variants + + + + + Tamil (Sri Lanka, TamilNet '99) + kb_variants + + + + + Tamil (Sri Lanka, TamilNet '99, TAB encoding) + kb_variants + + + + + Tamil (TamilNet '99 with Tamil numerals) + kb_variants + + + + + Tamil (TamilNet '99) + kb_variants + + + + + Tamil (TamilNet '99, TAB encoding) + kb_variants + + + + + Tamil (TamilNet '99, TSCII encoding) + kb_variants + + + + + Tatar + kb_variants + + + + + Telugu + kb_variants + + + + + Telugu (KaGaPa, phonetic) + kb_variants + + + + + Telugu (Sarala) + kb_variants + + + + + Thai (Pattachote) + kb_variants + + + + + Thai (TIS-820.2538) + kb_variants + + + + + Tibetan + kb_variants + + + + + Tibetan (with ASCII numerals) + kb_variants + + + + + Turkish (Alt-Q) + kb_variants + + + + + Turkish (F) + kb_variants + + + + + Turkish (Germany) + kb_variants + + + + + Turkish (Sun dead keys) + kb_variants + + + + + Turkish (intl., with dead keys) + kb_variants + + + + + Turkmen (Alt-Q) + kb_variants + + + + + Udmurt + kb_variants + + + + + Ukrainian (Windows) + kb_variants + + + + + Ukrainian (homophonic) + kb_variants + + + + + Ukrainian (legacy) + kb_variants + + + + + Ukrainian (phonetic) + kb_variants + + + + + Ukrainian (standard RSTU) + kb_variants + + + + + Ukrainian (typewriter) + kb_variants + + + + + Urdu (Pakistan, CRULP) + kb_variants + + + + + Urdu (Pakistan, NLA) + kb_variants + + + + + Urdu (Windows) + kb_variants + + + + + Urdu (alt. phonetic) + kb_variants + + + + + Urdu (phonetic) + kb_variants + + + + + Uyghur + kb_variants + + + + + Uzbek (Afghanistan) + kb_variants + + + + + Uzbek (Afghanistan, OLPC) + kb_variants + + + + + Uzbek (Latin) + kb_variants + + + + + Vietnamese (French) + kb_variants + + + + + Vietnamese (US) + kb_variants + + + + + Yakut + kb_variants + + + + + Yoruba + kb_variants + + + + diff --git a/lang/kb_tg.ts b/lang/kb_tg.ts new file mode 100644 index 000000000..893bed9ae --- /dev/null +++ b/lang/kb_tg.ts @@ -0,0 +1,4621 @@ + + + + + kb_layouts + + + Afghani + kb_layouts + Афғонӣ + + + + Albanian + kb_layouts + Албанӣ + + + + Amharic + kb_layouts + Амҳарӣ + + + + Arabic + kb_layouts + Арабӣ + + + + Arabic (Morocco) + kb_layouts + Арабӣ (Марокаш) + + + + Arabic (Syria) + kb_layouts + Арабӣ (Сурия) + + + + Armenian + kb_layouts + Арманӣ + + + + Azerbaijani + kb_layouts + Озарбойҷонӣ + + + + Bambara + kb_layouts + Бамбара + + + + Bangla + kb_layouts + Бангла + + + + Belarusian + kb_layouts + Белорусӣ + + + + Belgian + kb_layouts + Белгиягӣ + + + + Bosnian + kb_layouts + Босниягӣ + + + + Braille + kb_layouts + Брайл + + + + Bulgarian + kb_layouts + Булғорӣ + + + + Burmese + kb_layouts + Бирманӣ + + + + Chinese + kb_layouts + Хитоӣ + + + + Croatian + kb_layouts + Хорватӣ + + + + Czech + kb_layouts + Чехӣ + + + + Danish + kb_layouts + Даниягӣ + + + + Dhivehi + kb_layouts + Дхивеҳӣ + + + + Dutch + kb_layouts + Ҳоландӣ + + + + Dzongkha + kb_layouts + Дзонгха + + + + English (Australian) + kb_layouts + Англисӣ (Австралиягӣ) + + + + English (Cameroon) + kb_layouts + Англисӣ (Камерун) + + + + English (Ghana) + kb_layouts + Англисӣ (Гана) + + + + English (Nigeria) + kb_layouts + Англисӣ (Нигерия) + + + + English (South Africa) + kb_layouts + Англисӣ (Африкаи Ҷунубӣ) + + + + English (UK) + kb_layouts + Англисӣ (БК) + + + + English (US) + kb_layouts + Англисӣ (ИМА) + + + + Esperanto + kb_layouts + Эсперанто + + + + Estonian + kb_layouts + Эстонӣ + + + + Faroese + kb_layouts + Фарерӣ + + + + Filipino + kb_layouts + + + + + Finnish + kb_layouts + + + + + French + kb_layouts + + + + + French (Canada) + kb_layouts + + + + + French (Democratic Republic of the Congo) + kb_layouts + + + + + French (Guinea) + kb_layouts + + + + + French (Togo) + kb_layouts + + + + + Georgian + kb_layouts + + + + + German + kb_layouts + + + + + German (Austria) + kb_layouts + + + + + German (Switzerland) + kb_layouts + + + + + Greek + kb_layouts + + + + + Hebrew + kb_layouts + + + + + Hungarian + kb_layouts + + + + + Icelandic + kb_layouts + + + + + Indian + kb_layouts + + + + + Indonesian (Arab Melayu, phonetic) + kb_layouts + + + + + Indonesian (Javanese) + kb_layouts + + + + + Iraqi + kb_layouts + + + + + Irish + kb_layouts + + + + + Italian + kb_layouts + + + + + Japanese + kb_layouts + + + + + Japanese (PC-98) + kb_layouts + + + + + Kabylian (azerty layout, no dead keys) + kb_layouts + + + + + Kazakh + kb_layouts + + + + + Khmer (Cambodia) + kb_layouts + + + + + Korean + kb_layouts + + + + + Kyrgyz + kb_layouts + + + + + Lao + kb_layouts + + + + + Latvian + kb_layouts + + + + + Lithuanian + kb_layouts + + + + + Macedonian + kb_layouts + + + + + Malay (Jawi, Arabic Keyboard) + kb_layouts + + + + + Maltese + kb_layouts + + + + + Maori + kb_layouts + + + + + Moldavian + kb_layouts + + + + + Mongolian + kb_layouts + + + + + Montenegrin + kb_layouts + + + + + Nepali + kb_layouts + + + + + Norwegian + kb_layouts + + + + + Persian + kb_layouts + + + + + Polish + kb_layouts + + + + + Portuguese + kb_layouts + + + + + Portuguese (Brazil) + kb_layouts + + + + + Romanian + kb_layouts + + + + + Russian + kb_layouts + Русӣ + + + + Serbian + kb_layouts + + + + + Sinhala (phonetic) + kb_layouts + + + + + Slovak + kb_layouts + + + + + Slovenian + kb_layouts + + + + + Spanish + kb_layouts + + + + + Spanish (Latin American) + kb_layouts + + + + + Swahili (Kenya) + kb_layouts + + + + + Swahili (Tanzania) + kb_layouts + + + + + Swedish + kb_layouts + + + + + Taiwanese + kb_layouts + + + + + Tajik + kb_layouts + Тоҷикӣ + + + + Thai + kb_layouts + + + + + Tswana + kb_layouts + + + + + Turkish + kb_layouts + + + + + Turkmen + kb_layouts + Туркменӣ + + + + Ukrainian + kb_layouts + Украинӣ + + + + Urdu (Pakistan) + kb_layouts + + + + + Uzbek + kb_layouts + Ӯзбекӣ + + + + Vietnamese + kb_layouts + Ветнамӣ + + + + Wolof + kb_layouts + Волоф + + + + kb_models + + + A4Tech KB-21 + kb_models + A4Tech KB-21 + + + + A4Tech KBS-8 + kb_models + A4Tech KBS-8 + + + + A4Tech Wireless Desktop RFKB-23 + kb_models + Мизи кории бесими A4Tech RFKB-23 + + + + Acer AirKey V + kb_models + Acer AirKey V + + + + Acer C300 + kb_models + Acer C300 + + + + Acer Ferrari 4000 + kb_models + Acer Ferrari 4000 + + + + Acer laptop + kb_models + Лэптопи Acer + + + + Advance Scorpius KI + kb_models + Scorpius KI-и пешрафта + + + + Apple + kb_models + Apple + + + + Apple Aluminium (ANSI) + kb_models + Apple-и Алюминий (ANSI) + + + + Apple Aluminium (ISO) + kb_models + Apple-и Алюминий (ISO) + + + + Apple Aluminium (JIS) + kb_models + Apple-и Алюминий (JIS) + + + + Apple laptop + kb_models + Лэптопи Apple + + + + Asus laptop + kb_models + Лэптопи Asus + + + + Azona RF2300 wireless Internet + kb_models + Azona RF2300 Интернети бесим + + + + BTC 5090 + kb_models + BTC 5090 + + + + BTC 5113RF Multimedia + kb_models + BTC 5113RF Мултимедиа + + + + BTC 5126T + kb_models + BTC 5126T + + + + BTC 6301URF + kb_models + BTC 6301URF + + + + BTC 9000 + kb_models + BTC 9000 + + + + BTC 9000A + kb_models + BTC 9000A + + + + BTC 9001AH + kb_models + BTC 9001AH + + + + BTC 9019U + kb_models + BTC 9019U + + + + BTC 9116U Mini Wireless Internet and Gaming + kb_models + BTC 9116U Бозиҳо ва Интернети бесим (Хурд) + + + + BenQ X-Touch + kb_models + BenQ X-Touch + + + + BenQ X-Touch 730 + kb_models + BenQ X-Touch 730 + + + + BenQ X-Touch 800 + kb_models + BenQ X-Touch 800 + + + + Brother Internet + kb_models + Интернети бародарон + + + + Cherry B.UNLIMITED + kb_models + Черри, НОМАҲДУДИ B + + + + Cherry Blue Line CyBo@rd + kb_models + Черри, Хати кабуди CyBo@rd + + + + Cherry Blue Line CyBo@rd (alt.) + kb_models + Черри, Хати кабуди CyBo@rd. (илов.) + + + + Cherry CyBo@rd USB-Hub + kb_models + Черри, CyBo@rd USB-Hub + + + + Cherry CyMotion Expert + kb_models + Черри, Коршиноси CyMotion + + + + Cherry CyMotion Master Linux + kb_models + Черри, Устои Linux-и CyMotion + + + + Cherry CyMotion Master XPress + kb_models + Черри, Устои XPress-и CyMotion + + + + Chicony Internet + kb_models + Chicony-и интернетӣ + + + + Chicony KB-9885 + kb_models + Chicony KB-9885 + + + + Chicony KU-0108 + kb_models + Chicony KU-0108 + + + + Chicony KU-0420 + kb_models + Chicony KU-0420 + + + + Chromebook + kb_models + Хромбук + + + + Classmate PC + kb_models + Classmate PC + + + + Compaq Armada laptop + kb_models + Лэптопи Compaq Armada + + + + Compaq Easy Access + kb_models + Дастрасии осони Compaq + + + + Compaq Internet (13 keys) + kb_models + Compaq-и интернетӣ (13 тугма) + + + + Compaq Internet (18 keys) + kb_models + Compaq-и интернетӣ (18 тугма) + + + + Compaq Internet (7 keys) + kb_models + Compaq-и интернетӣ (7 тугма) + + + + Compaq Presario laptop + kb_models + Лэптопи Compaq Presario + + + + Compaq iPaq + kb_models + Compaq iPaq + + + + Creative Desktop Wireless 7000 + kb_models + Creative Desktop Wireless 7000 + + + + DTK2000 + kb_models + DTK2000 + + + + Dell + kb_models + Dell + + + + Dell 101-key PC + kb_models + Dell, 101 тугмаи компютерӣ + + + + Dell Inspiron 6000/8000 laptop + kb_models + Лэптопи Dell Inspiron 6000/8000 + + + + Dell Latitude laptop + kb_models + Лэптопи Dell Latitude + + + + Dell Precision M laptop + kb_models + Лэптопи Dell Precision M + + + + Dell Precision M65 laptop + kb_models + Лэптопи Dell Precision M65 + + + + Dell SK-8125 + kb_models + Dell SK-8125 + + + + Dell SK-8135 + kb_models + Dell SK-8135 + + + + Dell USB Multimedia + kb_models + Dell, Мултимедиаи USB + + + + Dexxa Wireless Desktop + kb_models + Мизи кории бесими Dexxa + + + + Diamond 9801/9802 + kb_models + Diamond 9801/9802 + + + + Ennyah DKB-1008 + kb_models + Ennyah DKB-1008 + + + + Everex STEPnote + kb_models + Everex STEPnote + + + + FL90 + kb_models + FL90 + + + + Fujitsu-Siemens Amilo laptop + kb_models + + + + + Generic 101-key PC + kb_models + Умумӣ, 101 тугмаи компютерӣ + + + + Generic 102-key PC + kb_models + Умумӣ, 102 тугмаи компютерӣ + + + + Generic 104-key PC + kb_models + Умумӣ, 104 тугмаи компютерӣ + + + + Generic 104-key PC with L-shaped Enter key + kb_models + Умумӣ, 104 тугмаи компютерӣ бо тугмаи Enter дар шакли L + + + + Generic 105-key PC + kb_models + Умумӣ, 105 тугмаи компютерӣ + + + + Generic 86-key PC + kb_models + Умумӣ, 86 тугмаи компютерӣ + + + + Genius Comfy KB-12e + kb_models + + + + + Genius Comfy KB-16M/Multimedia KWD-910 + kb_models + + + + + Genius Comfy KB-21e-Scroll + kb_models + + + + + Genius KB-19e NB + kb_models + + + + + Genius KKB-2050HS + kb_models + + + + + Gyration + kb_models + + + + + Happy Hacking + kb_models + + + + + Happy Hacking for Mac + kb_models + + + + + Hewlett-Packard Internet + kb_models + + + + + Hewlett-Packard Mini 110 laptop + kb_models + + + + + Hewlett-Packard NEC SK-2500 Multimedia + kb_models + + + + + Hewlett-Packard Omnibook 500 + kb_models + + + + + Hewlett-Packard Omnibook 500 FA + kb_models + + + + + Hewlett-Packard Omnibook 6000/6100 + kb_models + + + + + Hewlett-Packard Omnibook XE3 GC + kb_models + + + + + Hewlett-Packard Omnibook XE3 GF + kb_models + + + + + Hewlett-Packard Omnibook XT1000 + kb_models + + + + + Hewlett-Packard Pavilion ZT1100 + kb_models + + + + + Hewlett-Packard Pavilion dv5 + kb_models + + + + + Hewlett-Packard nx9020 + kb_models + + + + + Honeywell Euroboard + kb_models + + + + + IBM Rapid Access + kb_models + + + + + IBM Rapid Access II + kb_models + + + + + IBM Space Saver + kb_models + + + + + IBM ThinkPad 560Z/600/600E/A22E + kb_models + + + + + IBM ThinkPad R60/T60/R61/T61 + kb_models + + + + + IBM ThinkPad Z60m/Z60t/Z61m/Z61t + kb_models + + + + + Keytronic FlexPro + kb_models + + + + + Kinesis + kb_models + + + + + Logitech + kb_models + Logitech + + + + Logitech Access + kb_models + Logitech Access + + + + Logitech Cordless Desktop + kb_models + + + + + Logitech Cordless Desktop (alt.) + kb_models + + + + + Logitech Cordless Desktop EX110 + kb_models + + + + + Logitech Cordless Desktop LX-300 + kb_models + + + + + Logitech Cordless Desktop Navigator + kb_models + + + + + Logitech Cordless Desktop Optical + kb_models + + + + + Logitech Cordless Desktop Pro (2nd alt.) + kb_models + + + + + Logitech Cordless Desktop iTouch + kb_models + + + + + Logitech Cordless Freedom/Desktop Navigator + kb_models + + + + + Logitech G15 extra keys via G15daemon + kb_models + + + + + Logitech Internet + kb_models + + + + + Logitech Internet 350 + kb_models + + + + + Logitech Internet Navigator + kb_models + + + + + Logitech Ultra-X + kb_models + + + + + Logitech Ultra-X Cordless Media Desktop + kb_models + + + + + Logitech diNovo + kb_models + + + + + Logitech diNovo Edge + kb_models + + + + + Logitech iTouch + kb_models + + + + + Logitech iTouch Cordless Y-RB6 + kb_models + + + + + Logitech iTouch Internet Navigator SE + kb_models + + + + + Logitech iTouch Internet Navigator SE USB + kb_models + + + + + MacBook/MacBook Pro + kb_models + + + + + MacBook/MacBook Pro (intl.) + kb_models + + + + + Macintosh + kb_models + + + + + Macintosh Old + kb_models + + + + + Memorex MX1998 + kb_models + Memorex MX1998 + + + + Memorex MX2500 EZ-Access + kb_models + Memorex MX2500 EZ-Access + + + + Memorex MX2750 + kb_models + Memorex MX2750 + + + + Microsoft Comfort Curve 2000 + kb_models + Microsoft Comfort Curve 2000 + + + + Microsoft Internet + kb_models + + + + + Microsoft Internet Pro (Swedish) + kb_models + + + + + Microsoft Natural + kb_models + + + + + Microsoft Natural Elite + kb_models + + + + + Microsoft Natural Ergonomic 4000 + kb_models + + + + + Microsoft Natural Pro OEM + kb_models + + + + + Microsoft Natural Pro USB/Internet Pro + kb_models + + + + + Microsoft Natural Pro/Internet Pro + kb_models + + + + + Microsoft Natural Wireless Ergonomic 7000 + kb_models + + + + + Microsoft Office Keyboard + kb_models + + + + + Microsoft Surface + kb_models + + + + + Microsoft Wireless Multimedia 1.0A + kb_models + + + + + NEC SK-1300 + kb_models + NEC SK-1300 + + + + NEC SK-2500 + kb_models + NEC SK-2500 + + + + NEC SK-6200 + kb_models + NEC SK-6200 + + + + NEC SK-7100 + kb_models + NEC SK-7100 + + + + Northgate OmniKey 101 + kb_models + + + + + OLPC + kb_models + OLPC + + + + Ortek Multimedia/Internet MCK-800 + kb_models + + + + + PC-98 + kb_models + + + + + Propeller Voyager KTEZ-1000 + kb_models + + + + + QTronix Scorpius 98N+ + kb_models + + + + + SVEN Ergonomic 2500 + kb_models + SVEN Ergonomic 2500 + + + + SVEN Slim 303 + kb_models + SVEN Slim 303 + + + + Samsung SDM 4500P + kb_models + Samsung SDM 4500P + + + + Samsung SDM 4510P + kb_models + Samsung SDM 4510P + + + + Sanwa Supply SKB-KG3 + kb_models + + + + + Silvercrest Multimedia Wireless + kb_models + + + + + SteelSeries Apex 300 (Apex RAW) + kb_models + + + + + Sun Type 6 (Japanese) + kb_models + + + + + Sun Type 6 USB (Japanese) + kb_models + + + + + Sun Type 6 USB (Unix) + kb_models + + + + + Sun Type 6/7 USB + kb_models + + + + + Sun Type 6/7 USB (European) + kb_models + + + + + Sun Type 7 USB + kb_models + + + + + Sun Type 7 USB (European) + kb_models + + + + + Sun Type 7 USB (Japanese)/Japanese 106-key + kb_models + + + + + Sun Type 7 USB (Unix) + kb_models + + + + + Super Power Multimedia + kb_models + + + + + Symplon PaceBook tablet + kb_models + + + + + Targa Visionary 811 + kb_models + + + + + Toshiba Satellite S3000 + kb_models + + + + + Truly Ergonomic 227 + kb_models + + + + + Truly Ergonomic 229 + kb_models + + + + + Truly Ergonomic Computer Keyboard Model 227 (Wide Alt keys) + kb_models + + + + + Truly Ergonomic Computer Keyboard Model 229 (Standard sized Alt keys, additional Super and Menu key) + kb_models + + + + + Trust Direct Access + kb_models + + + + + Trust Slimline + kb_models + + + + + Trust Wireless Classic + kb_models + + + + + TypeMatrix EZ-Reach 2020 + kb_models + TypeMatrix EZ-Reach 2020 + + + + TypeMatrix EZ-Reach 2030 PS2 + kb_models + TypeMatrix EZ-Reach 2030 PS2 + + + + TypeMatrix EZ-Reach 2030 USB + kb_models + TypeMatrix EZ-Reach 2030 USB + + + + TypeMatrix EZ-Reach 2030 USB (102/105:EU mode) + kb_models + TypeMatrix EZ-Reach 2030 USB (Реҷаи 102/105:EU) + + + + TypeMatrix EZ-Reach 2030 USB (106:JP mode) + kb_models + TypeMatrix EZ-Reach 2030 USB (Реҷаи 106:JP) + + + + Unitek KB-1925 + kb_models + Unitek KB-1925 + + + + ViewSonic KU-306 Internet + kb_models + ViewSonic KU-306-и интернетӣ + + + + Winbook Model XP5 + kb_models + + + + + Yahoo! Internet + kb_models + Yahoo! Интернет + + + + eMachines m6800 laptop + kb_models + Лэптопи eMachines m6800 + + + + kb_variants + + + Akan + kb_variants + Аконӣ + + + + Albanian (Plisi) + kb_variants + Албанӣ (Плисӣ) + + + + Albanian (Veqilharxhi) + kb_variants + Албанӣ (Векилхаркшӣ) + + + + Arabic (AZERTY) + kb_variants + Арабӣ (AZERTY) + + + + Arabic (AZERTY, Eastern Arabic numerals) + kb_variants + Арабӣ (AZERTY, Рақамҳои арабии шаркӣ) + + + + Arabic (Algeria) + kb_variants + Арабӣ (Алҷазоир) + + + + Arabic (Buckwalter) + kb_variants + Арабӣ (Бакуолтер) + + + + Arabic (Eastern Arabic numerals) + kb_variants + Арабӣ (Рақамҳои арабии шаркӣ) + + + + Arabic (Macintosh) + kb_variants + Арабӣ (Макинтош) + + + + Arabic (OLPC) + kb_variants + Арабӣ (OLPC) + + + + Arabic (Pakistan) + kb_variants + Арабӣ (Покистон) + + + + Arabic (QWERTY) + kb_variants + Арабӣ (QWERTY) + + + + Arabic (QWERTY, Eastern Arabic numerals) + kb_variants + Арабӣ (QWERTY, Рақамҳои арабии шаркӣ) + + + + Armenian (alt. eastern) + kb_variants + Арманӣ (илов. шарқӣ) + + + + Armenian (alt. phonetic) + kb_variants + Арманӣ (илов. фонетикӣ) + + + + Armenian (eastern) + kb_variants + Арманӣ (шарқӣ) + + + + Armenian (phonetic) + kb_variants + Арманӣ (фонетикӣ) + + + + Armenian (western) + kb_variants + Арманӣ (ғарбӣ) + + + + Asturian (Spain, with bottom-dot H and L) + kb_variants + Астурӣ (Испания, бо нуқтаи поёни H ва L) + + + + Avatime + kb_variants + Avatime + + + + Azerbaijani (Cyrillic) + kb_variants + Озарбойҷонӣ (Кириллӣ) + + + + Bangla (India) + kb_variants + Бангла (Ҳиндустон) + + + + Bangla (India, Baishakhi Inscript) + kb_variants + Бангла (Ҳиндустон, Инскрипти Байшахӣ) + + + + Bangla (India, Baishakhi) + kb_variants + Бангла (Ҳиндустон, Байшахӣ) + + + + Bangla (India, Bornona) + kb_variants + Бангла (Ҳиндустон, Борнона) + + + + Bangla (India, Gitanjali) + kb_variants + Бангла (Ҳиндустон, Гитанҷалӣ) + + + + Bangla (India, Probhat) + kb_variants + Бангла (Ҳиндустон, Пробхат) + + + + Bangla (Probhat) + kb_variants + Бангла (Пробхат) + + + + Bashkirian + kb_variants + Бошқирдӣ + + + + Belarusian (Latin) + kb_variants + Белорусӣ (Лотинӣ) + + + + Belarusian (intl.) + kb_variants + Белорусӣ (байналм.) + + + + Belarusian (legacy) + kb_variants + Белорусӣ (ворисӣ) + + + + Belgian (ISO, alt.) + kb_variants + Белгиягӣ (ISO, илов.) + + + + Belgian (Latin-9 only, alt.) + kb_variants + Белгиягӣ (Танҳо лотинии-9, илов.) + + + + Belgian (Sun dead keys) + kb_variants + Белгиягӣ (Тугмаҳои хомӯшии Sun) + + + + Belgian (Sun dead keys, alt.) + kb_variants + Белгиягӣ (Тугмаҳои хомӯшии Sun, илов.) + + + + Belgian (Wang 724 AZERTY) + kb_variants + Белгиягӣ (Ванг 724 AZERTY) + + + + Belgian (alt.) + kb_variants + Белгиягӣ (илов.) + + + + Belgian (no dead keys) + kb_variants + Белгиягӣ (бе тугмаҳои хомӯшӣ) + + + + Berber (Morocco, Tifinagh alt.) + kb_variants + Берберӣ (Марокаш, Тифинагҳӣ, илов.) + + + + Berber (Morocco, Tifinagh extended phonetic) + kb_variants + Берберӣ (Марокаш, Тифинагҳӣ, фонетикии васеъшуда) + + + + Berber (Morocco, Tifinagh extended) + kb_variants + Берберӣ (Марокаш, Тифинагҳӣ, васеъшуда) + + + + Berber (Morocco, Tifinagh phonetic) + kb_variants + Берберӣ (Марокаш, Тифинагҳӣ, фонетикӣ) + + + + Berber (Morocco, Tifinagh phonetic, alt.) + kb_variants + Берберӣ (Марокаш, Тифинагҳӣ, фонетикӣ, илов.) + + + + Berber (Morocco, Tifinagh) + kb_variants + Берберӣ (Марокаш, Тифинагҳӣ) + + + + Bosnian (US) + kb_variants + Босниягӣ (ИМА) + + + + Bosnian (US, with Bosnian digraphs) + kb_variants + Босниягӣ (ИМА, бо диграфҳои босниягӣ) + + + + Bosnian (with Bosnian digraphs) + kb_variants + Босниягӣ (бо диграфҳои босниягӣ) + + + + Bosnian (with guillemets) + kb_variants + Босниягӣ (бо гиллеметҳо) + + + + Braille (left-handed inverted thumb) + kb_variants + Брайл (сарангушти чаппаи дасти чап) + + + + Braille (left-handed) + kb_variants + Брайл (дасти чап) + + + + Braille (right-handed inverted thumb) + kb_variants + Брайл (сарангушти чаппаи дасти рост) + + + + Braille (right-handed) + kb_variants + Брайл (дасти рост) + + + + Bulgarian (enhanced) + kb_variants + Булғорӣ (такмилёфта) + + + + Bulgarian (new phonetic) + kb_variants + Булғорӣ (фонетикии нав) + + + + Bulgarian (traditional phonetic) + kb_variants + Булғорӣ (фонетикии анъанавӣ) + + + + Burmese Zawgyi + kb_variants + Бирмании завҷӣ + + + + Cameroon (AZERTY, intl.) + kb_variants + Камерун (AZERTY, байналм.) + + + + Cameroon (Dvorak, intl.) + kb_variants + Камерун (Дворак, байналм.) + + + + Cameroon Multilingual (QWERTY, intl.) + kb_variants + Камеруни серзабон (QWERTY, байналм.) + + + + Canadian (intl.) + kb_variants + Канадагӣ (байналм.) + + + + Canadian (intl., 1st part) + kb_variants + Канадагӣ (байналм. қисми 1) + + + + Canadian (intl., 2nd part) + kb_variants + Канадагӣ (байналм. қисми 2) + + + + Catalan (Spain, with middle-dot L) + kb_variants + Каталонӣ (Испания, бо нуқтаи миёнаи L) + + + + Cherokee + kb_variants + Черокӣ + + + + Chuvash + kb_variants + Чувашӣ + + + + Chuvash (Latin) + kb_variants + Чувашӣ (Лотинӣ) + + + + CloGaelach + kb_variants + CloGaelach + + + + Crimean Tatar (Turkish Alt-Q) + kb_variants + Тотории кримӣ (Туркӣ, Alt-Q) + + + + Crimean Tatar (Turkish F) + kb_variants + Тотории кримӣ (F-и туркӣ) + + + + Crimean Tatar (Turkish Q) + kb_variants + Тотории кримӣ (Q-и туркӣ) + + + + Croatian (US) + kb_variants + Хорватӣ (ИМА) + + + + Croatian (US, with Croatian digraphs) + kb_variants + Хорватӣ (ИМА, бо диграфҳои хорватӣ) + + + + Croatian (with Croatian digraphs) + kb_variants + Хорватӣ (бо диграфҳои хорватӣ) + + + + Croatian (with guillemets) + kb_variants + Хорватӣ (бо гиллеметҳо) + + + + Czech (QWERTY) + kb_variants + Чехӣ (QWERTY) + + + + Czech (QWERTY, Macintosh) + kb_variants + Чехӣ (QWERTY, Макинтош) + + + + Czech (QWERTY, extended backslash) + kb_variants + Чехӣ (QWERTY, аломати хати каҷи баръакси васеъшуда) + + + + Czech (UCW, only accented letters) + kb_variants + Чехӣ (UCW, танҳо ҳарфҳои вижагӣ) + + + + Czech (US, Dvorak, UCW support) + kb_variants + Чехӣ (ИМА, Дворак, дастгирии UCW) + + + + Czech (with &lt;|&gt; key) + kb_variants + Чехӣ (бо тугмаи &lt;|&gt;) + + + + Danish (Dvorak) + kb_variants + Даниягӣ (Дворак) + + + + Danish (Macintosh) + kb_variants + Даниягӣ (Макинтош) + + + + Danish (Macintosh, no dead keys) + kb_variants + Даниягӣ (Макинтош, бе тугмаҳои хомӯшӣ) + + + + Danish (Windows) + kb_variants + Даниягӣ (Windows) + + + + Danish (no dead keys) + kb_variants + Даниягӣ (бе тугмаҳои хомӯшӣ) + + + + Default + kb_variants + Стандартӣ + + + + Dutch (Macintosh) + kb_variants + Ҳоландӣ (Макинтош) + + + + Dutch (Sun dead keys) + kb_variants + Ҳоландӣ (Тугмаҳои хомӯшии Sun) + + + + Dutch (standard) + kb_variants + Ҳоландӣ (стандартӣ) + + + + English (Canada) + kb_variants + Англисӣ (Канада) + + + + English (Colemak) + kb_variants + Англисӣ (Колемак) + + + + English (Dvorak) + kb_variants + Англисӣ (Дворак) + + + + English (Dvorak, alt. intl.) + kb_variants + Англисӣ (Дворак, илов. байналм.) + + + + English (Dvorak, intl., with dead keys) + kb_variants + Англисӣ (Дворак, байналм. бо тугмаҳои хомӯшӣ) + + + + English (Dvorak, left-handed) + kb_variants + Англисӣ (Дворак, дасти чап) + + + + English (Dvorak, right-handed) + kb_variants + Англисӣ (Дворак, дасти рост) + + + + English (Ghana, GILLBT) + kb_variants + Англисӣ (Гана, GILLBT) + + + + English (Ghana, multilingual) + kb_variants + Англисӣ (Гана, серзабон) + + + + English (India, with rupee) + kb_variants + Англисӣ (Ҳиндустон, бо рупия) + + + + English (Macintosh) + kb_variants + Англисӣ (Макинтош) + + + + English (Mali, US, Macintosh) + kb_variants + Англисӣ (Малӣ, ИМА, Макинтош) + + + + English (Mali, US, intl.) + kb_variants + Англисӣ (Малӣ, ИМА, байналм.) + + + + English (Norman) + kb_variants + Англисӣ (Норман) + + + + English (UK, Colemak) + kb_variants + Англисӣ (БК, Колемак) + + + + English (UK, Dvorak) + kb_variants + Англисӣ (БК, Дворак) + + + + English (UK, Dvorak, with UK punctuation) + kb_variants + Англисӣ (БК, Дворак, бо аломатҳои китобатӣ) + + + + English (UK, Macintosh) + kb_variants + Англисӣ (БК, Макинтош) + + + + English (UK, Macintosh, intl.) + kb_variants + Англисӣ (БК, Макинтош, байналм.) + + + + English (UK, extended, Windows) + kb_variants + Англисӣ (БК, васеъшуда, Windows) + + + + English (UK, intl., with dead keys) + kb_variants + Англисӣ (БК, байналм., бо тугмаҳои хомӯшӣ) + + + + English (US, Symbolic) + kb_variants + Англисӣ (ИМА, Рамзӣ) + + + + English (US, alt. intl.) + kb_variants + Англисӣ (ИМА, илов. байналм.) + + + + English (US, euro on 5) + kb_variants + Англисӣ (ИМА, евро дар 5) + + + + English (US, intl., with dead keys) + kb_variants + Англисӣ (ИМА, байналм., бо тугмаҳои хомӯшӣ) + + + + English (Workman) + kb_variants + Англисӣ (Воркман) + + + + English (Workman, intl., with dead keys) + kb_variants + Англисӣ (Воркман, байналм., бо тугмаҳои хомӯшӣ) + + + + English (classic Dvorak) + kb_variants + Англисӣ (Двораки классикӣ) + + + + English (intl., with AltGr dead keys) + kb_variants + Англисӣ (байналм., бо тугмаҳои хомӯшии AltGr) + + + + English (programmer Dvorak) + kb_variants + Англисӣ (Двораки барномарезӣ) + + + + English (the divide/multiply toggle the layout) + kb_variants + Англисӣ (тарҳбандӣ бо алоҳида/якчанд васлкунак) + + + + Esperanto (Brazil, Nativo) + kb_variants + Эсперанто (Бразилия, Нативо) + + + + Esperanto (Portugal, Nativo) + kb_variants + Эсперанто (Португалия, Нативо) + + + + Esperanto (legacy) + kb_variants + Эсперанто (ворисӣ) + + + + Estonian (Dvorak) + kb_variants + Эстонӣ (Дворак) + + + + Estonian (US) + kb_variants + Эстонӣ (ИМА) + + + + Estonian (no dead keys) + kb_variants + Эстонӣ (бе тугмаҳои хомӯшӣ) + + + + Ewe + kb_variants + Ewe + + + + Faroese (no dead keys) + kb_variants + Фарерӣ (бе тугмаҳои хомӯшӣ) + + + + Filipino (Capewell-Dvorak, Baybayin) + kb_variants + + + + + Filipino (Capewell-Dvorak, Latin) + kb_variants + + + + + Filipino (Capewell-QWERF 2006, Baybayin) + kb_variants + + + + + Filipino (Capewell-QWERF 2006, Latin) + kb_variants + + + + + Filipino (Colemak, Baybayin) + kb_variants + + + + + Filipino (Colemak, Latin) + kb_variants + + + + + Filipino (Dvorak, Baybayin) + kb_variants + + + + + Filipino (Dvorak, Latin) + kb_variants + + + + + Filipino (QWERTY, Baybayin) + kb_variants + + + + + Finnish (Macintosh) + kb_variants + + + + + Finnish (Windows) + kb_variants + + + + + Finnish (classic) + kb_variants + + + + + Finnish (classic, no dead keys) + kb_variants + + + + + French (AZERTY) + kb_variants + + + + + French (AZERTY, AFNOR) + kb_variants + + + + + French (BEPO) + kb_variants + + + + + French (BEPO, AFNOR) + kb_variants + + + + + French (BEPO, Latin-9 only) + kb_variants + + + + + French (Breton) + kb_variants + + + + + French (Cameroon) + kb_variants + + + + + French (Canada, Dvorak) + kb_variants + + + + + French (Canada, legacy) + kb_variants + + + + + French (Dvorak) + kb_variants + + + + + French (Macintosh) + kb_variants + + + + + French (Mali, alt.) + kb_variants + + + + + French (Morocco) + kb_variants + + + + + French (Sun dead keys) + kb_variants + + + + + French (Switzerland) + kb_variants + + + + + French (Switzerland, Macintosh) + kb_variants + + + + + French (Switzerland, Sun dead keys) + kb_variants + + + + + French (Switzerland, no dead keys) + kb_variants + + + + + French (US) + kb_variants + + + + + French (alt.) + kb_variants + + + + + French (alt., Latin-9 only) + kb_variants + + + + + French (alt., Sun dead keys) + kb_variants + + + + + French (alt., no dead keys) + kb_variants + + + + + French (legacy, alt.) + kb_variants + + + + + French (legacy, alt., Sun dead keys) + kb_variants + + + + + French (legacy, alt., no dead keys) + kb_variants + + + + + French (no dead keys) + kb_variants + + + + + Friulian (Italy) + kb_variants + + + + + Fula + kb_variants + + + + + Ga + kb_variants + + + + + Georgian (France, AZERTY Tskapo) + kb_variants + + + + + Georgian (Italy) + kb_variants + + + + + Georgian (MESS) + kb_variants + + + + + Georgian (ergonomic) + kb_variants + + + + + German (Austria, Macintosh) + kb_variants + + + + + German (Austria, Sun dead keys) + kb_variants + + + + + German (Austria, no dead keys) + kb_variants + + + + + German (Dvorak) + kb_variants + + + + + German (E1) + kb_variants + + + + + German (E2) + kb_variants + + + + + German (Macintosh) + kb_variants + + + + + German (Macintosh, no dead keys) + kb_variants + + + + + German (Neo 2) + kb_variants + + + + + German (QWERTY) + kb_variants + + + + + German (Sun dead keys) + kb_variants + + + + + German (Switzerland, Macintosh) + kb_variants + + + + + German (Switzerland, Sun dead keys) + kb_variants + + + + + German (Switzerland, legacy) + kb_variants + + + + + German (Switzerland, no dead keys) + kb_variants + + + + + German (T3) + kb_variants + + + + + German (US) + kb_variants + + + + + German (dead acute) + kb_variants + + + + + German (dead grave acute) + kb_variants + + + + + German (dead tilde) + kb_variants + + + + + German (no dead keys) + kb_variants + + + + + Greek (extended) + kb_variants + + + + + Greek (no dead keys) + kb_variants + + + + + Greek (polytonic) + kb_variants + + + + + Greek (simple) + kb_variants + + + + + Gujarati + kb_variants + + + + + Hanyu Pinyin (with AltGr dead keys) + kb_variants + + + + + Hausa (Ghana) + kb_variants + + + + + Hausa (Nigeria) + kb_variants + + + + + Hawaiian + kb_variants + + + + + Hebrew (Biblical, Tiro) + kb_variants + + + + + Hebrew (lyx) + kb_variants + + + + + Hebrew (phonetic) + kb_variants + + + + + Hindi (Bolnagri) + kb_variants + + + + + Hindi (KaGaPa, phonetic) + kb_variants + + + + + Hindi (Wx) + kb_variants + + + + + Hungarian (QWERTY) + kb_variants + + + + + Hungarian (QWERTY, 101-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 101-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTY, 101-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 101-key, dot, no dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTY, 102-key, dot, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 101-key, dot, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, comma, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, comma, no dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, dot, dead keys) + kb_variants + + + + + Hungarian (QWERTZ, 102-key, dot, no dead keys) + kb_variants + + + + + Hungarian (no dead keys) + kb_variants + + + + + Hungarian (standard) + kb_variants + + + + + Icelandic (Dvorak) + kb_variants + + + + + Icelandic (Macintosh) + kb_variants + + + + + Icelandic (Macintosh, legacy) + kb_variants + + + + + Icelandic (Sun dead keys) + kb_variants + + + + + Icelandic (no dead keys) + kb_variants + + + + + Igbo + kb_variants + + + + + Indic (phonetic, IPA) + kb_variants + + + + + Indonesian (Arab Melayu, extended phonetic) + kb_variants + + + + + Inuktitut + kb_variants + + + + + Irish (UnicodeExpert) + kb_variants + + + + + Italian (IBM 142) + kb_variants + + + + + Italian (Macintosh) + kb_variants + + + + + Italian (US) + kb_variants + + + + + Italian (Windows) + kb_variants + + + + + Italian (intl., with dead keys) + kb_variants + + + + + Italian (no dead keys) + kb_variants + + + + + Japanese (Dvorak) + kb_variants + + + + + Japanese (Kana 86) + kb_variants + + + + + Japanese (Kana) + kb_variants + + + + + Japanese (Macintosh) + kb_variants + + + + + Japanese (OADG 109A) + kb_variants + + + + + Kabylian (Algeria, Tifinagh) + kb_variants + + + + + Kabylian (azerty layout, with dead keys) + kb_variants + + + + + Kabylian (qwerty-gb layout, with dead keys) + kb_variants + + + + + Kabylian (qwerty-us layout, with dead keys) + kb_variants + + + + + Kalmyk + kb_variants + + + + + Kannada + kb_variants + + + + + Kannada (KaGaPa, phonetic) + kb_variants + + + + + Kashubian + kb_variants + + + + + Kazakh (Latin) + kb_variants + + + + + Kazakh (extended) + kb_variants + + + + + Kazakh (with Russian) + kb_variants + + + + + Kikuyu + kb_variants + + + + + Komi + kb_variants + + + + + Korean (101/104-key compatible) + kb_variants + + + + + Kurdish (Iran, Arabic-Latin) + kb_variants + + + + + Kurdish (Iran, F) + kb_variants + + + + + Kurdish (Iran, Latin Alt-Q) + kb_variants + + + + + Kurdish (Iran, Latin Q) + kb_variants + + + + + Kurdish (Iraq, Arabic-Latin) + kb_variants + + + + + Kurdish (Iraq, F) + kb_variants + + + + + Kurdish (Iraq, Latin Alt-Q) + kb_variants + + + + + Kurdish (Iraq, Latin Q) + kb_variants + + + + + Kurdish (Syria, F) + kb_variants + + + + + Kurdish (Syria, Latin Alt-Q) + kb_variants + + + + + Kurdish (Syria, Latin Q) + kb_variants + + + + + Kurdish (Turkey, F) + kb_variants + + + + + Kurdish (Turkey, Latin Alt-Q) + kb_variants + + + + + Kurdish (Turkey, Latin Q) + kb_variants + + + + + Kyrgyz (phonetic) + kb_variants + + + + + Lao (STEA) + kb_variants + + + + + Latvian (F) + kb_variants + + + + + Latvian (adapted) + kb_variants + + + + + Latvian (apostrophe) + kb_variants + + + + + Latvian (ergonomic, ŪGJRMV) + kb_variants + + + + + Latvian (modern) + kb_variants + + + + + Latvian (tilde) + kb_variants + + + + + Lithuanian (IBM LST 1205-92) + kb_variants + + + + + Lithuanian (LEKP) + kb_variants + + + + + Lithuanian (LEKPa) + kb_variants + + + + + Lithuanian (US) + kb_variants + + + + + Lithuanian (standard) + kb_variants + + + + + Lower Sorbian + kb_variants + + + + + Lower Sorbian (QWERTZ) + kb_variants + + + + + Macedonian (no dead keys) + kb_variants + + + + + Malay (Jawi, phonetic) + kb_variants + + + + + Malayalam + kb_variants + + + + + Malayalam (Lalitha) + kb_variants + + + + + Malayalam (enhanced Inscript, with rupee) + kb_variants + + + + + Maltese (UK, with AltGr overrides) + kb_variants + + + + + Maltese (US layout with AltGr overrides) + kb_variants + + + + + Maltese (US) + kb_variants + + + + + Manipuri (Eeyek) + kb_variants + + + + + Marathi (KaGaPa, phonetic) + kb_variants + + + + + Marathi (enhanced Inscript) + kb_variants + + + + + Mari + kb_variants + + + + + Mmuock + kb_variants + + + + + Moldavian (Gagauz) + kb_variants + + + + + Mongolian (Bichig) + kb_variants + + + + + Mongolian (Galik) + kb_variants + + + + + Mongolian (Manchu Galik) + kb_variants + + + + + Mongolian (Manchu) + kb_variants + + + + + Mongolian (Todo Galik) + kb_variants + + + + + Mongolian (Todo) + kb_variants + + + + + Mongolian (Xibe) + kb_variants + + + + + Montenegrin (Cyrillic) + kb_variants + + + + + Montenegrin (Cyrillic, ZE and ZHE swapped) + kb_variants + + + + + Montenegrin (Cyrillic, with guillemets) + kb_variants + + + + + Montenegrin (Latin, QWERTY) + kb_variants + + + + + Montenegrin (Latin, Unicode) + kb_variants + + + + + Montenegrin (Latin, Unicode, QWERTY) + kb_variants + + + + + Montenegrin (Latin, with guillemets) + kb_variants + + + + + Northern Saami (Finland) + kb_variants + + + + + Northern Saami (Norway) + kb_variants + + + + + Northern Saami (Norway, no dead keys) + kb_variants + + + + + Northern Saami (Sweden) + kb_variants + + + + + Norwegian (Colemak) + kb_variants + + + + + Norwegian (Dvorak) + kb_variants + + + + + Norwegian (Macintosh) + kb_variants + + + + + Norwegian (Macintosh, no dead keys) + kb_variants + + + + + Norwegian (Windows) + kb_variants + + + + + Norwegian (no dead keys) + kb_variants + + + + + Occitan + kb_variants + + + + + Ogham + kb_variants + + + + + Ogham (IS434) + kb_variants + + + + + Ol Chiki + kb_variants + + + + + Oriya + kb_variants + + + + + Ossetian (Georgia) + kb_variants + + + + + Ossetian (Windows) + kb_variants + + + + + Ossetian (legacy) + kb_variants + + + + + Pannonian Rusyn + kb_variants + + + + + Pashto + kb_variants + + + + + Pashto (Afghanistan, OLPC) + kb_variants + + + + + Persian (Afghanistan, Dari OLPC) + kb_variants + + + + + Persian (with Persian keypad) + kb_variants + + + + + Polish (British keyboard) + kb_variants + + + + + Polish (Dvorak) + kb_variants + + + + + Polish (Dvorak, with Polish quotes on key 1) + kb_variants + + + + + Polish (Dvorak, with Polish quotes on quotemark key) + kb_variants + + + + + Polish (QWERTZ) + kb_variants + + + + + Polish (legacy) + kb_variants + + + + + Polish (programmer Dvorak) + kb_variants + + + + + Portuguese (Brazil, Dvorak) + kb_variants + + + + + Portuguese (Brazil, IBM/Lenovo ThinkPad) + kb_variants + + + + + Portuguese (Brazil, Nativo for US keyboards) + kb_variants + + + + + Portuguese (Brazil, Nativo) + kb_variants + + + + + Portuguese (Brazil, no dead keys) + kb_variants + + + + + Portuguese (Macintosh) + kb_variants + + + + + Portuguese (Macintosh, Sun dead keys) + kb_variants + + + + + Portuguese (Macintosh, no dead keys) + kb_variants + + + + + Portuguese (Nativo for US keyboards) + kb_variants + + + + + Portuguese (Nativo) + kb_variants + + + + + Portuguese (Sun dead keys) + kb_variants + + + + + Portuguese (no dead keys) + kb_variants + + + + + Punjabi (Gurmukhi Jhelum) + kb_variants + + + + + Punjabi (Gurmukhi) + kb_variants + + + + + Romanian (Germany) + kb_variants + + + + + Romanian (Germany, no dead keys) + kb_variants + + + + + Romanian (Windows) + kb_variants + + + + + Romanian (cedilla) + kb_variants + + + + + Romanian (standard cedilla) + kb_variants + + + + + Romanian (standard) + kb_variants + + + + + Russian (Belarus) + kb_variants + Русӣ (Беларус) + + + + Russian (Czech, phonetic) + kb_variants + Русӣ (Чехӣ, фонетикӣ) + + + + Russian (DOS) + kb_variants + Русӣ (DOS) + + + + Russian (Georgia) + kb_variants + Русӣ (Гурҷӣ) + + + + Russian (Germany, phonetic) + kb_variants + Русӣ (Немисӣ, фонетикӣ) + + + + Russian (Kazakhstan, with Kazakh) + kb_variants + Русӣ (Қазоқистон, бо қазоқӣ) + + + + Russian (Macintosh) + kb_variants + Русӣ (Макинтош) + + + + Russian (Poland, phonetic Dvorak) + kb_variants + Русӣ (Полша, Дворакии фонетикӣ) + + + + Russian (Sweden, phonetic) + kb_variants + Русӣ (Шведӣ, фонетикӣ) + + + + Russian (Sweden, phonetic, no dead keys) + kb_variants + Русӣ (Шведӣ, фонетикӣ, бе тугмаҳои хомӯшӣ) + + + + Russian (US, phonetic) + kb_variants + Русӣ (ИМА, фонетикӣ) + + + + Russian (Ukraine, standard RSTU) + kb_variants + Русӣ (Украина, RSTU-и стандартӣ) + + + + Russian (legacy) + kb_variants + Русӣ (ворисӣ) + + + + Russian (phonetic) + kb_variants + Русӣ (фонетикӣ) + + + + Russian (phonetic, AZERTY) + kb_variants + Русӣ (фонетикӣ, AZERTY) + + + + Russian (phonetic, Dvorak) + kb_variants + Русӣ (фонетикӣ, Дворак) + + + + Russian (phonetic, French) + kb_variants + Русӣ (фонетикӣ, Франсузӣ) + + + + Russian (phonetic, Windows) + kb_variants + Русӣ (фонетикӣ, Windows) + + + + Russian (phonetic, YAZHERTY) + kb_variants + Русӣ (фонетикӣ, YAZHERTY) + + + + Russian (typewriter) + kb_variants + Русӣ (мошини хатнависӣ) + + + + Russian (typewriter, legacy) + kb_variants + Русӣ (мошини хатнависӣ, ворисӣ) + + + + Saisiyat (Taiwan) + kb_variants + + + + + Samogitian + kb_variants + + + + + Sanskrit (KaGaPa, phonetic) + kb_variants + + + + + Serbian (Cyrillic, ZE and ZHE swapped) + kb_variants + + + + + Serbian (Cyrillic, with guillemets) + kb_variants + + + + + Serbian (Latin) + kb_variants + + + + + Serbian (Latin, QWERTY) + kb_variants + + + + + Serbian (Latin, Unicode) + kb_variants + + + + + Serbian (Latin, Unicode, QWERTY) + kb_variants + + + + + Serbian (Latin, with guillemets) + kb_variants + + + + + Serbian (Russia) + kb_variants + + + + + Serbo-Croatian (US) + kb_variants + + + + + Sicilian + kb_variants + + + + + Silesian + kb_variants + + + + + Sindhi + kb_variants + + + + + Sinhala (US) + kb_variants + + + + + Slovak (QWERTY) + kb_variants + + + + + Slovak (QWERTY, extended backslash) + kb_variants + + + + + Slovak (extended backslash) + kb_variants + + + + + Slovenian (US) + kb_variants + + + + + Slovenian (with guillemets) + kb_variants + + + + + Spanish (Dvorak) + kb_variants + + + + + Spanish (Latin American, Colemak for gaming) + kb_variants + + + + + Spanish (Latin American, Colemak) + kb_variants + + + + + Spanish (Latin American, Dvorak) + kb_variants + + + + + Spanish (Latin American, Sun dead keys) + kb_variants + + + + + Spanish (Latin American, dead tilde) + kb_variants + + + + + Spanish (Latin American, no dead keys) + kb_variants + + + + + Spanish (Macintosh) + kb_variants + + + + + Spanish (Sun dead keys) + kb_variants + + + + + Spanish (Windows) + kb_variants + + + + + Spanish (dead tilde) + kb_variants + + + + + Spanish (no dead keys) + kb_variants + + + + + Swedish (Dvorak) + kb_variants + + + + + Swedish (Dvorak, intl.) + kb_variants + + + + + Swedish (Macintosh) + kb_variants + + + + + Swedish (Svdvorak) + kb_variants + + + + + Swedish (US) + kb_variants + + + + + Swedish (no dead keys) + kb_variants + + + + + Swedish Sign Language + kb_variants + + + + + Syriac + kb_variants + + + + + Syriac (phonetic) + kb_variants + + + + + Taiwanese (indigenous) + kb_variants + + + + + Tajik (legacy) + kb_variants + Тоҷикӣ (ворисӣ) + + + + Tamil (Inscript) + kb_variants + + + + + Tamil (Sri Lanka, TamilNet '99) + kb_variants + + + + + Tamil (Sri Lanka, TamilNet '99, TAB encoding) + kb_variants + + + + + Tamil (TamilNet '99 with Tamil numerals) + kb_variants + + + + + Tamil (TamilNet '99) + kb_variants + + + + + Tamil (TamilNet '99, TAB encoding) + kb_variants + + + + + Tamil (TamilNet '99, TSCII encoding) + kb_variants + + + + + Tatar + kb_variants + Тоторӣ + + + + Telugu + kb_variants + + + + + Telugu (KaGaPa, phonetic) + kb_variants + + + + + Telugu (Sarala) + kb_variants + + + + + Thai (Pattachote) + kb_variants + + + + + Thai (TIS-820.2538) + kb_variants + + + + + Tibetan + kb_variants + + + + + Tibetan (with ASCII numerals) + kb_variants + + + + + Turkish (Alt-Q) + kb_variants + + + + + Turkish (F) + kb_variants + + + + + Turkish (Germany) + kb_variants + + + + + Turkish (Sun dead keys) + kb_variants + + + + + Turkish (intl., with dead keys) + kb_variants + + + + + Turkmen (Alt-Q) + kb_variants + Туркменӣ (Alt-Q) + + + + Udmurt + kb_variants + Удмуртӣ + + + + Ukrainian (Windows) + kb_variants + Украинӣ (Windows) + + + + Ukrainian (homophonic) + kb_variants + Украинӣ (гомофонӣ) + + + + Ukrainian (legacy) + kb_variants + Украинӣ (ворисӣ) + + + + Ukrainian (phonetic) + kb_variants + Украинӣ (фонетикӣ) + + + + Ukrainian (standard RSTU) + kb_variants + Украинӣ (RSTU-и стандартӣ) + + + + Ukrainian (typewriter) + kb_variants + Украинӣ (мошини хатнависӣ) + + + + Urdu (Pakistan, CRULP) + kb_variants + + + + + Urdu (Pakistan, NLA) + kb_variants + + + + + Urdu (Windows) + kb_variants + + + + + Urdu (alt. phonetic) + kb_variants + + + + + Urdu (phonetic) + kb_variants + + + + + Uyghur + kb_variants + Ӯйғурӣ + + + + Uzbek (Afghanistan) + kb_variants + Ӯзбекӣ (Афғонистон) + + + + Uzbek (Afghanistan, OLPC) + kb_variants + Ӯзбекӣ (Афғонистон, OLPC) + + + + Uzbek (Latin) + kb_variants + Ӯзбекӣ (Лотинӣ) + + + + Vietnamese (French) + kb_variants + Ветнамӣ (Франсузӣ) + + + + Vietnamese (US) + kb_variants + Ветнамӣ (ИМА) + + + + Yakut + kb_variants + Ёқутӣ + + + + Yoruba + kb_variants + Йоруба + + + diff --git a/lang/python.pot b/lang/python.pot index 5dc844031..1de1081b7 100644 --- a/lang/python.pot +++ b/lang/python.pot @@ -2,32 +2,32 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. -# +# #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-10-16 22:35+0200\n" +"POT-Creation-Date: 2020-11-09 15:12+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: \n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: src/modules/grubcfg/main.py:28 msgid "Configure GRUB." -msgstr "Configure GRUB." +msgstr "" -#: src/modules/mount/main.py:29 +#: src/modules/mount/main.py:30 msgid "Mounting partitions." -msgstr "Mounting partitions." +msgstr "" -#: src/modules/mount/main.py:141 src/modules/initcpiocfg/main.py:196 -#: src/modules/initcpiocfg/main.py:200 +#: src/modules/mount/main.py:127 src/modules/initcpiocfg/main.py:199 +#: src/modules/initcpiocfg/main.py:203 #: src/modules/luksopenswaphookcfg/main.py:86 #: src/modules/luksopenswaphookcfg/main.py:90 src/modules/rawfs/main.py:164 #: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89 @@ -36,327 +36,312 @@ msgstr "Mounting partitions." #: src/modules/fstab/main.py:367 src/modules/localecfg/main.py:135 #: src/modules/networkcfg/main.py:39 msgid "Configuration Error" -msgstr "Configuration Error" +msgstr "" -#: src/modules/mount/main.py:142 src/modules/initcpiocfg/main.py:197 +#: src/modules/mount/main.py:128 src/modules/initcpiocfg/main.py:200 #: src/modules/luksopenswaphookcfg/main.py:87 src/modules/rawfs/main.py:165 #: src/modules/initramfscfg/main.py:86 src/modules/openrcdmcryptcfg/main.py:70 #: src/modules/fstab/main.py:362 msgid "No partitions are defined for
{!s}
to use." -msgstr "No partitions are defined for
{!s}
to use." +msgstr "" #: src/modules/services-systemd/main.py:26 msgid "Configure systemd services" -msgstr "Configure systemd services" +msgstr "" #: src/modules/services-systemd/main.py:59 #: src/modules/services-openrc/main.py:93 msgid "Cannot modify service" -msgstr "Cannot modify service" +msgstr "" #: src/modules/services-systemd/main.py:60 msgid "" "systemctl {arg!s} call in chroot returned error code {num!s}." msgstr "" -"systemctl {arg!s} call in chroot returned error code {num!s}." #: src/modules/services-systemd/main.py:63 #: src/modules/services-systemd/main.py:67 msgid "Cannot enable systemd service {name!s}." -msgstr "Cannot enable systemd service {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:65 msgid "Cannot enable systemd target {name!s}." -msgstr "Cannot enable systemd target {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:69 msgid "Cannot disable systemd target {name!s}." -msgstr "Cannot disable systemd target {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:71 msgid "Cannot mask systemd unit {name!s}." -msgstr "Cannot mask systemd unit {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:73 msgid "" -"Unknown systemd commands {command!s} and " -"{suffix!s} for unit {name!s}." +"Unknown systemd commands {command!s} and {suffix!s} for unit {name!s}." msgstr "" -"Unknown systemd commands {command!s} and " -"{suffix!s} for unit {name!s}." #: src/modules/umount/main.py:31 msgid "Unmount file systems." -msgstr "Unmount file systems." +msgstr "" #: src/modules/unpackfs/main.py:35 msgid "Filling up filesystems." -msgstr "Filling up filesystems." +msgstr "" #: src/modules/unpackfs/main.py:254 msgid "rsync failed with error code {}." -msgstr "rsync failed with error code {}." +msgstr "" #: src/modules/unpackfs/main.py:299 msgid "Unpacking image {}/{}, file {}/{}" -msgstr "Unpacking image {}/{}, file {}/{}" +msgstr "" #: src/modules/unpackfs/main.py:314 msgid "Starting to unpack {}" -msgstr "Starting to unpack {}" +msgstr "" #: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:463 msgid "Failed to unpack image \"{}\"" -msgstr "Failed to unpack image \"{}\"" +msgstr "" #: src/modules/unpackfs/main.py:430 msgid "No mount point for root partition" -msgstr "No mount point for root partition" +msgstr "" #: src/modules/unpackfs/main.py:431 msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" -msgstr "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" +msgstr "" #: src/modules/unpackfs/main.py:436 msgid "Bad mount point for root partition" -msgstr "Bad mount point for root partition" +msgstr "" #: src/modules/unpackfs/main.py:437 msgid "rootMountPoint is \"{}\", which does not exist, doing nothing" -msgstr "rootMountPoint is \"{}\", which does not exist, doing nothing" +msgstr "" #: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457 #: src/modules/unpackfs/main.py:477 msgid "Bad unsquash configuration" -msgstr "Bad unsquash configuration" +msgstr "" #: src/modules/unpackfs/main.py:454 msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel" -msgstr "The filesystem for \"{}\" ({}) is not supported by your current kernel" +msgstr "" #: src/modules/unpackfs/main.py:458 msgid "The source filesystem \"{}\" does not exist" -msgstr "The source filesystem \"{}\" does not exist" +msgstr "" #: src/modules/unpackfs/main.py:464 msgid "" "Failed to find unsquashfs, make sure you have the squashfs-tools package " "installed" msgstr "" -"Failed to find unsquashfs, make sure you have the squashfs-tools package " -"installed" #: src/modules/unpackfs/main.py:478 msgid "The destination \"{}\" in the target system is not a directory" -msgstr "The destination \"{}\" in the target system is not a directory" +msgstr "" #: src/modules/displaymanager/main.py:514 msgid "Cannot write KDM configuration file" -msgstr "Cannot write KDM configuration file" +msgstr "" #: src/modules/displaymanager/main.py:515 msgid "KDM config file {!s} does not exist" -msgstr "KDM config file {!s} does not exist" +msgstr "" #: src/modules/displaymanager/main.py:576 msgid "Cannot write LXDM configuration file" -msgstr "Cannot write LXDM configuration file" +msgstr "" #: src/modules/displaymanager/main.py:577 msgid "LXDM config file {!s} does not exist" -msgstr "LXDM config file {!s} does not exist" +msgstr "" #: src/modules/displaymanager/main.py:660 msgid "Cannot write LightDM configuration file" -msgstr "Cannot write LightDM configuration file" +msgstr "" #: src/modules/displaymanager/main.py:661 msgid "LightDM config file {!s} does not exist" -msgstr "LightDM config file {!s} does not exist" +msgstr "" #: src/modules/displaymanager/main.py:735 msgid "Cannot configure LightDM" -msgstr "Cannot configure LightDM" +msgstr "" #: src/modules/displaymanager/main.py:736 msgid "No LightDM greeter installed." -msgstr "No LightDM greeter installed." +msgstr "" #: src/modules/displaymanager/main.py:767 msgid "Cannot write SLIM configuration file" -msgstr "Cannot write SLIM configuration file" +msgstr "" #: src/modules/displaymanager/main.py:768 msgid "SLIM config file {!s} does not exist" -msgstr "SLIM config file {!s} does not exist" +msgstr "" #: src/modules/displaymanager/main.py:894 msgid "No display managers selected for the displaymanager module." -msgstr "No display managers selected for the displaymanager module." +msgstr "" #: src/modules/displaymanager/main.py:895 msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" -"The displaymanagers list is empty or undefined in both globalstorage and " -"displaymanager.conf." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" -msgstr "Display manager configuration was incomplete" +msgstr "" #: src/modules/initcpiocfg/main.py:28 msgid "Configuring mkinitcpio." -msgstr "Configuring mkinitcpio." +msgstr "" -#: src/modules/initcpiocfg/main.py:201 +#: src/modules/initcpiocfg/main.py:204 #: src/modules/luksopenswaphookcfg/main.py:91 #: src/modules/initramfscfg/main.py:90 src/modules/openrcdmcryptcfg/main.py:74 #: src/modules/fstab/main.py:368 src/modules/localecfg/main.py:136 #: src/modules/networkcfg/main.py:40 msgid "No root mount point is given for
{!s}
to use." -msgstr "No root mount point is given for
{!s}
to use." +msgstr "" #: src/modules/luksopenswaphookcfg/main.py:26 msgid "Configuring encrypted swap." -msgstr "Configuring encrypted swap." +msgstr "" #: src/modules/rawfs/main.py:26 msgid "Installing data." -msgstr "Installing data." +msgstr "" #: src/modules/services-openrc/main.py:29 msgid "Configure OpenRC services" -msgstr "Configure OpenRC services" +msgstr "" #: src/modules/services-openrc/main.py:57 msgid "Cannot add service {name!s} to run-level {level!s}." -msgstr "Cannot add service {name!s} to run-level {level!s}." +msgstr "" #: src/modules/services-openrc/main.py:59 msgid "Cannot remove service {name!s} from run-level {level!s}." -msgstr "Cannot remove service {name!s} from run-level {level!s}." +msgstr "" #: src/modules/services-openrc/main.py:61 msgid "" "Unknown service-action {arg!s} for service {name!s} in run-" "level {level!s}." msgstr "" -"Unknown service-action {arg!s} for service {name!s} in run-" -"level {level!s}." #: src/modules/services-openrc/main.py:94 msgid "" "rc-update {arg!s} call in chroot returned error code {num!s}." msgstr "" -"rc-update {arg!s} call in chroot returned error code {num!s}." #: src/modules/services-openrc/main.py:101 msgid "Target runlevel does not exist" -msgstr "Target runlevel does not exist" +msgstr "" #: src/modules/services-openrc/main.py:102 msgid "" "The path for runlevel {level!s} is {path!s}, which does not " "exist." msgstr "" -"The path for runlevel {level!s} is {path!s}, which does not " -"exist." #: src/modules/services-openrc/main.py:110 msgid "Target service does not exist" -msgstr "Target service does not exist" +msgstr "" #: src/modules/services-openrc/main.py:111 msgid "" -"The path for service {name!s} is {path!s}, which does not " -"exist." +"The path for service {name!s} is {path!s}, which does not exist." msgstr "" -"The path for service {name!s} is {path!s}, which does not " -"exist." #: src/modules/plymouthcfg/main.py:27 msgid "Configure Plymouth theme" -msgstr "Configure Plymouth theme" +msgstr "" #: src/modules/packages/main.py:50 src/modules/packages/main.py:59 #: src/modules/packages/main.py:69 msgid "Install packages." -msgstr "Install packages." +msgstr "" #: src/modules/packages/main.py:57 #, python-format msgid "Processing packages (%(count)d / %(total)d)" -msgstr "Processing packages (%(count)d / %(total)d)" +msgstr "" #: src/modules/packages/main.py:62 #, python-format msgid "Installing one package." msgid_plural "Installing %(num)d packages." -msgstr[0] "Installing one package." -msgstr[1] "Installing %(num)d packages." +msgstr[0] "" +msgstr[1] "" #: src/modules/packages/main.py:65 #, python-format msgid "Removing one package." msgid_plural "Removing %(num)d packages." -msgstr[0] "Removing one package." -msgstr[1] "Removing %(num)d packages." +msgstr[0] "" +msgstr[1] "" #: src/modules/bootloader/main.py:42 msgid "Install bootloader." -msgstr "Install bootloader." +msgstr "" #: src/modules/hwclock/main.py:26 msgid "Setting hardware clock." -msgstr "Setting hardware clock." +msgstr "" #: src/modules/mkinitfs/main.py:27 msgid "Creating initramfs with mkinitfs." -msgstr "Creating initramfs with mkinitfs." +msgstr "" #: src/modules/mkinitfs/main.py:49 msgid "Failed to run mkinitfs on the target" -msgstr "Failed to run mkinitfs on the target" +msgstr "" #: src/modules/mkinitfs/main.py:50 src/modules/dracut/main.py:50 msgid "The exit code was {}" -msgstr "The exit code was {}" +msgstr "" #: src/modules/dracut/main.py:27 msgid "Creating initramfs with dracut." -msgstr "Creating initramfs with dracut." +msgstr "" #: src/modules/dracut/main.py:49 msgid "Failed to run dracut on the target" -msgstr "Failed to run dracut on the target" +msgstr "" #: src/modules/initramfscfg/main.py:32 msgid "Configuring initramfs." -msgstr "Configuring initramfs." +msgstr "" #: src/modules/openrcdmcryptcfg/main.py:25 msgid "Configuring OpenRC dmcrypt service." -msgstr "Configuring OpenRC dmcrypt service." +msgstr "" #: src/modules/fstab/main.py:29 msgid "Writing fstab." -msgstr "Writing fstab." +msgstr "" #: src/modules/dummypython/main.py:35 msgid "Dummy python job." -msgstr "Dummy python job." +msgstr "" #: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93 #: src/modules/dummypython/main.py:94 msgid "Dummy python step {}" -msgstr "Dummy python step {}" +msgstr "" #: src/modules/localecfg/main.py:30 msgid "Configuring locales." -msgstr "Configuring locales." +msgstr "" #: src/modules/networkcfg/main.py:28 msgid "Saving network configuration." -msgstr "Saving network configuration." +msgstr "" diff --git a/lang/python/az/LC_MESSAGES/python.po b/lang/python/az/LC_MESSAGES/python.po index 516429c2d..8637bfe7e 100644 --- a/lang/python/az/LC_MESSAGES/python.po +++ b/lang/python/az/LC_MESSAGES/python.po @@ -206,6 +206,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Ekran menecerləri siyahısı həm qlobal yaddaşda, həm də displaymanager.conf-" +"da boşdur və ya təyin olunmamışdır." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/az_AZ/LC_MESSAGES/python.po b/lang/python/az_AZ/LC_MESSAGES/python.po index 5fdf99797..4fb1f949b 100644 --- a/lang/python/az_AZ/LC_MESSAGES/python.po +++ b/lang/python/az_AZ/LC_MESSAGES/python.po @@ -206,6 +206,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Ekran menecerləri siyahısı həm qlobal yaddaşda, həm də displaymanager.conf-" +"da boşdur və ya təyin olunmamışdır." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" @@ -318,11 +320,11 @@ msgstr "Aparat saatını ayarlamaq." #: src/modules/mkinitfs/main.py:27 msgid "Creating initramfs with mkinitfs." -msgstr "mkinitfs ilə initramfs yaradılır." +msgstr "mkinitfs ilə initramfs yaradılır" #: src/modules/mkinitfs/main.py:49 msgid "Failed to run mkinitfs on the target" -msgstr "Hədəfdə dracut başladılmadı" +msgstr "Hədəfdə mkinitfs başlatmaq baş tutmadı" #: src/modules/mkinitfs/main.py:50 src/modules/dracut/main.py:50 msgid "The exit code was {}" diff --git a/lang/python/be/LC_MESSAGES/python.po b/lang/python/be/LC_MESSAGES/python.po index c31beab74..b9154868b 100644 --- a/lang/python/be/LC_MESSAGES/python.po +++ b/lang/python/be/LC_MESSAGES/python.po @@ -201,6 +201,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Спіс дысплейных кіраўнікоў пусты альбо не вызначаны ў both globalstorage і " +"displaymanager.conf." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" @@ -314,11 +316,11 @@ msgstr "Наладка апаратнага гадзінніка." #: src/modules/mkinitfs/main.py:27 msgid "Creating initramfs with mkinitfs." -msgstr "" +msgstr "Стварэнне initramfs праз mkinitfs." #: src/modules/mkinitfs/main.py:49 msgid "Failed to run mkinitfs on the target" -msgstr "" +msgstr "Не атрымалася запусціць mkinitfs у пункце прызначэння" #: src/modules/mkinitfs/main.py:50 src/modules/dracut/main.py:50 msgid "The exit code was {}" diff --git a/lang/python/bg/LC_MESSAGES/python.po b/lang/python/bg/LC_MESSAGES/python.po index 372847af8..ca58592ad 100644 --- a/lang/python/bg/LC_MESSAGES/python.po +++ b/lang/python/bg/LC_MESSAGES/python.po @@ -4,7 +4,7 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Georgi Georgiev, 2020 +# Жоро, 2020 # #, fuzzy msgid "" @@ -13,7 +13,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-10-16 22:35+0200\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n" -"Last-Translator: Georgi Georgiev, 2020\n" +"Last-Translator: Жоро, 2020\n" "Language-Team: Bulgarian (https://www.transifex.com/calamares/teams/20061/bg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/lang/python/ca/LC_MESSAGES/python.po b/lang/python/ca/LC_MESSAGES/python.po index 3d057cae1..1dc1d6d14 100644 --- a/lang/python/ca/LC_MESSAGES/python.po +++ b/lang/python/ca/LC_MESSAGES/python.po @@ -204,6 +204,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"La llista de gestors de pantalla és buida o no definida ni a globalstorage " +"ni a displaymanager.conf." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/da/LC_MESSAGES/python.po b/lang/python/da/LC_MESSAGES/python.po index e2603ca82..6a103acbe 100644 --- a/lang/python/da/LC_MESSAGES/python.po +++ b/lang/python/da/LC_MESSAGES/python.po @@ -204,6 +204,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Displayhåndteringerlisten er tom eller udefineret i både globalstorage og " +"displaymanager.conf." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/de/LC_MESSAGES/python.po b/lang/python/de/LC_MESSAGES/python.po index e67f06089..6dd5b751d 100644 --- a/lang/python/de/LC_MESSAGES/python.po +++ b/lang/python/de/LC_MESSAGES/python.po @@ -4,9 +4,9 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Andreas Eitel , 2020 # Adriaan de Groot , 2020 # Christian Spaan, 2020 +# Andreas Eitel , 2020 # #, fuzzy msgid "" @@ -15,7 +15,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-10-16 22:35+0200\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n" -"Last-Translator: Christian Spaan, 2020\n" +"Last-Translator: Andreas Eitel , 2020\n" "Language-Team: German (https://www.transifex.com/calamares/teams/20061/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -208,6 +208,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Die Liste der Displaymanager ist leer oder weder in globalstorage noch in " +"displaymanager.conf definiert." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/fi_FI/LC_MESSAGES/python.po b/lang/python/fi_FI/LC_MESSAGES/python.po index cb15f9ae9..e4e63e57d 100644 --- a/lang/python/fi_FI/LC_MESSAGES/python.po +++ b/lang/python/fi_FI/LC_MESSAGES/python.po @@ -201,6 +201,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Luettelo on tyhjä tai määrittelemätön, sekä globalstorage, että " +"displaymanager.conf tiedostossa." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/fur/LC_MESSAGES/python.po b/lang/python/fur/LC_MESSAGES/python.po index 3168c2f35..90800f4a2 100644 --- a/lang/python/fur/LC_MESSAGES/python.po +++ b/lang/python/fur/LC_MESSAGES/python.po @@ -23,11 +23,11 @@ msgstr "" #: src/modules/grubcfg/main.py:28 msgid "Configure GRUB." -msgstr "" +msgstr "Configure GRUB." #: src/modules/mount/main.py:29 msgid "Mounting partitions." -msgstr "" +msgstr "Montaç des partizions." #: src/modules/mount/main.py:141 src/modules/initcpiocfg/main.py:196 #: src/modules/initcpiocfg/main.py:200 diff --git a/lang/python/hi/LC_MESSAGES/python.po b/lang/python/hi/LC_MESSAGES/python.po index 2b0ab266a..d577d9fd8 100644 --- a/lang/python/hi/LC_MESSAGES/python.po +++ b/lang/python/hi/LC_MESSAGES/python.po @@ -200,6 +200,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"globalstorage व displaymanager.conf में डिस्प्ले प्रबंधक सूची रिक्त या " +"अपरिभाषित है।" #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/ko/LC_MESSAGES/python.po b/lang/python/ko/LC_MESSAGES/python.po index 7108fb0e0..8b8a891e8 100644 --- a/lang/python/ko/LC_MESSAGES/python.po +++ b/lang/python/ko/LC_MESSAGES/python.po @@ -4,7 +4,7 @@ # FIRST AUTHOR , YEAR. # # Translators: -# 김지현 , 2018 +# Ji-Hyeon Gim , 2018 # JungHee Lee , 2020 # #, fuzzy diff --git a/lang/python/sv/LC_MESSAGES/python.po b/lang/python/sv/LC_MESSAGES/python.po index 0b8665e7a..d1c87de4c 100644 --- a/lang/python/sv/LC_MESSAGES/python.po +++ b/lang/python/sv/LC_MESSAGES/python.po @@ -205,6 +205,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Skärmhanterar listan är tom eller odefinierad i både globalstorage och " +"displaymanager.conf." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/tg/LC_MESSAGES/python.po b/lang/python/tg/LC_MESSAGES/python.po index d99c9e711..d9886a107 100644 --- a/lang/python/tg/LC_MESSAGES/python.po +++ b/lang/python/tg/LC_MESSAGES/python.po @@ -205,6 +205,8 @@ msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" +"Рӯйхати displaymanagers ҳам дар globalstorage ва ҳам дар displaymanager.conf" +" холӣ ё номаълум аст." #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/python/vi/LC_MESSAGES/python.po b/lang/python/vi/LC_MESSAGES/python.po new file mode 100644 index 000000000..bb9b67a96 --- /dev/null +++ b/lang/python/vi/LC_MESSAGES/python.po @@ -0,0 +1,363 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +# Translators: +# T. Tran , 2020 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-10-16 22:35+0200\n" +"PO-Revision-Date: 2017-08-09 10:34+0000\n" +"Last-Translator: T. Tran , 2020\n" +"Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: vi\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: src/modules/grubcfg/main.py:28 +msgid "Configure GRUB." +msgstr "Cấu hình GRUB" + +#: src/modules/mount/main.py:29 +msgid "Mounting partitions." +msgstr "Đang gắn kết các phân vùng." + +#: src/modules/mount/main.py:141 src/modules/initcpiocfg/main.py:196 +#: src/modules/initcpiocfg/main.py:200 +#: src/modules/luksopenswaphookcfg/main.py:86 +#: src/modules/luksopenswaphookcfg/main.py:90 src/modules/rawfs/main.py:164 +#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89 +#: src/modules/openrcdmcryptcfg/main.py:69 +#: src/modules/openrcdmcryptcfg/main.py:73 src/modules/fstab/main.py:361 +#: src/modules/fstab/main.py:367 src/modules/localecfg/main.py:135 +#: src/modules/networkcfg/main.py:39 +msgid "Configuration Error" +msgstr "Lỗi cấu hình" + +#: src/modules/mount/main.py:142 src/modules/initcpiocfg/main.py:197 +#: src/modules/luksopenswaphookcfg/main.py:87 src/modules/rawfs/main.py:165 +#: src/modules/initramfscfg/main.py:86 src/modules/openrcdmcryptcfg/main.py:70 +#: src/modules/fstab/main.py:362 +msgid "No partitions are defined for
{!s}
to use." +msgstr "Không có phân vùng nào được định nghĩa cho
{!s}
để dùng." + +#: src/modules/services-systemd/main.py:26 +msgid "Configure systemd services" +msgstr "Cấu hình các dịch vụ systemd" + +#: src/modules/services-systemd/main.py:59 +#: src/modules/services-openrc/main.py:93 +msgid "Cannot modify service" +msgstr "Không thể sửa đổi dịch vụ" + +#: src/modules/services-systemd/main.py:60 +msgid "" +"systemctl {arg!s} call in chroot returned error code {num!s}." +msgstr "" +"systemctl {arg!s} trong môi trường chroot trả về lỗi {num!s}." + +#: src/modules/services-systemd/main.py:63 +#: src/modules/services-systemd/main.py:67 +msgid "Cannot enable systemd service {name!s}." +msgstr "Không thể bật dịch vụ systemd {name!s}." + +#: src/modules/services-systemd/main.py:65 +msgid "Cannot enable systemd target {name!s}." +msgstr "Không thể bật nhóm dịch vụ systemd {name!s}." + +#: src/modules/services-systemd/main.py:69 +msgid "Cannot disable systemd target {name!s}." +msgstr "Không thể tắt nhóm dịch vụ systemd {name!s}." + +#: src/modules/services-systemd/main.py:71 +msgid "Cannot mask systemd unit {name!s}." +msgstr "Không thể đánh dấu đơn vị systemd {name!s}." + +#: src/modules/services-systemd/main.py:73 +msgid "" +"Unknown systemd commands {command!s} and " +"{suffix!s} for unit {name!s}." +msgstr "" +"Không nhận ra lệnh systemd {command!s} và " +"{suffix!s} cho đơn vị {name!s}." + +#: src/modules/umount/main.py:31 +msgid "Unmount file systems." +msgstr "Gỡ kết nối các hệ thống tập tin." + +#: src/modules/unpackfs/main.py:35 +msgid "Filling up filesystems." +msgstr "Đang làm đầy các hệ thống tập tin." + +#: src/modules/unpackfs/main.py:254 +msgid "rsync failed with error code {}." +msgstr "rsync thất bại với lỗi {}." + +#: src/modules/unpackfs/main.py:299 +msgid "Unpacking image {}/{}, file {}/{}" +msgstr "Đang bung hình ảnh {}/{}, tập tin {}/{}" + +#: src/modules/unpackfs/main.py:314 +msgid "Starting to unpack {}" +msgstr "Bắt đầu bung nội dung {}" + +#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:463 +msgid "Failed to unpack image \"{}\"" +msgstr "Bung hình ảnh thất bại \"{}\"" + +#: src/modules/unpackfs/main.py:430 +msgid "No mount point for root partition" +msgstr "Không có điểm kết nối cho phân vùng gốc" + +#: src/modules/unpackfs/main.py:431 +msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" +msgstr "globalstorage không có khoá \"rootMountPoint\", sẽ không làm gì cả" + +#: src/modules/unpackfs/main.py:436 +msgid "Bad mount point for root partition" +msgstr "Sai điểm kết nối cho phân vùng gốc" + +#: src/modules/unpackfs/main.py:437 +msgid "rootMountPoint is \"{}\", which does not exist, doing nothing" +msgstr "rootMountPoint không tồn tại, có giá trị là \"{}\", sẽ không làm gì cả" + +#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457 +#: src/modules/unpackfs/main.py:477 +msgid "Bad unsquash configuration" +msgstr "Sai cấu hình bung nén" + +#: src/modules/unpackfs/main.py:454 +msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel" +msgstr "Hệ thống tập tin cho \"{}\" ({}) không được hỗ trợ bởi nhân hiện tại" + +#: src/modules/unpackfs/main.py:458 +msgid "The source filesystem \"{}\" does not exist" +msgstr "Hệ thống tập tin nguồn \"{}\" không tồn tại" + +#: src/modules/unpackfs/main.py:464 +msgid "" +"Failed to find unsquashfs, make sure you have the squashfs-tools package " +"installed" +msgstr "Không tìm thấy lệnh unsquashfs, vui lòng cài đặt gói squashfs-tools" + +#: src/modules/unpackfs/main.py:478 +msgid "The destination \"{}\" in the target system is not a directory" +msgstr "Hệ thống đích \"{}\" không phải là một thư mục" + +#: src/modules/displaymanager/main.py:514 +msgid "Cannot write KDM configuration file" +msgstr "Không thể ghi vào tập tin cấu hình KDM" + +#: src/modules/displaymanager/main.py:515 +msgid "KDM config file {!s} does not exist" +msgstr "Tập tin cấu hình KDM {!s} không tồn tại" + +#: src/modules/displaymanager/main.py:576 +msgid "Cannot write LXDM configuration file" +msgstr "Không thể ghi vào tập tin cấu hình LXDM" + +#: src/modules/displaymanager/main.py:577 +msgid "LXDM config file {!s} does not exist" +msgstr "Tập tin cấu hình LXDM {!s} không tồn tại" + +#: src/modules/displaymanager/main.py:660 +msgid "Cannot write LightDM configuration file" +msgstr "Không thể ghi vào tập tin cấu hình LightDM" + +#: src/modules/displaymanager/main.py:661 +msgid "LightDM config file {!s} does not exist" +msgstr "Tập tin cấu hình LightDM {!s} không tồn tại" + +#: src/modules/displaymanager/main.py:735 +msgid "Cannot configure LightDM" +msgstr "Không thể cấu hình LXDM" + +#: src/modules/displaymanager/main.py:736 +msgid "No LightDM greeter installed." +msgstr "Màn hình chào mừng LightDM không được cài đặt." + +#: src/modules/displaymanager/main.py:767 +msgid "Cannot write SLIM configuration file" +msgstr "Không thể ghi vào tập tin cấu hình SLIM" + +#: src/modules/displaymanager/main.py:768 +msgid "SLIM config file {!s} does not exist" +msgstr "Tập tin cấu hình SLIM {!s} không tồn tại" + +#: src/modules/displaymanager/main.py:894 +msgid "No display managers selected for the displaymanager module." +msgstr "" +"Không có trình quản lý hiển thị nào được chọn cho mô-đun quản lý hiển thị" + +#: src/modules/displaymanager/main.py:895 +msgid "" +"The displaymanagers list is empty or undefined in both globalstorage and " +"displaymanager.conf." +msgstr "" +"Danh sách quản lý hiện thị trống hoặc không được định nghĩa cả trong " +"globalstorage và displaymanager.conf." + +#: src/modules/displaymanager/main.py:977 +msgid "Display manager configuration was incomplete" +msgstr "Cầu hình quản lý hiện thị không hoàn tất" + +#: src/modules/initcpiocfg/main.py:28 +msgid "Configuring mkinitcpio." +msgstr "Đang cấu hình mkinitcpio." + +#: src/modules/initcpiocfg/main.py:201 +#: src/modules/luksopenswaphookcfg/main.py:91 +#: src/modules/initramfscfg/main.py:90 src/modules/openrcdmcryptcfg/main.py:74 +#: src/modules/fstab/main.py:368 src/modules/localecfg/main.py:136 +#: src/modules/networkcfg/main.py:40 +msgid "No root mount point is given for
{!s}
to use." +msgstr "Không có điểm kết nối gốc cho
{!s}
để dùng." + +#: src/modules/luksopenswaphookcfg/main.py:26 +msgid "Configuring encrypted swap." +msgstr "Đang cấu hình hoán đổi mã hoá" + +#: src/modules/rawfs/main.py:26 +msgid "Installing data." +msgstr "Đang cài đặt dữ liệu." + +#: src/modules/services-openrc/main.py:29 +msgid "Configure OpenRC services" +msgstr "Cấu hình dịch vụ OpenRC" + +#: src/modules/services-openrc/main.py:57 +msgid "Cannot add service {name!s} to run-level {level!s}." +msgstr "Không thể thêm dịch vụ {name!s} vào run-level {level!s}." + +#: src/modules/services-openrc/main.py:59 +msgid "Cannot remove service {name!s} from run-level {level!s}." +msgstr "Không thể loại bỏ dịch vụ {name!s} từ run-level {level!s}." + +#: src/modules/services-openrc/main.py:61 +msgid "" +"Unknown service-action {arg!s} for service {name!s} in run-" +"level {level!s}." +msgstr "" +"Không nhận ra thao tác {arg!s} cho dịch vụ {name!s} ở run-level" +" {level!s}." + +#: src/modules/services-openrc/main.py:94 +msgid "" +"rc-update {arg!s} call in chroot returned error code {num!s}." +msgstr "" +"Lệnh rc-update {arg!s} trong môi trường chroot trả về lỗi " +"{num!s}." + +#: src/modules/services-openrc/main.py:101 +msgid "Target runlevel does not exist" +msgstr "Nhóm dịch vụ khởi động không tồn tại" + +#: src/modules/services-openrc/main.py:102 +msgid "" +"The path for runlevel {level!s} is {path!s}, which does not " +"exist." +msgstr "" +"Đường dẫn cho runlevel {level!s} là {path!s}, nhưng không tồn " +"tại." + +#: src/modules/services-openrc/main.py:110 +msgid "Target service does not exist" +msgstr "Nhóm dịch vụ không tồn tại" + +#: src/modules/services-openrc/main.py:111 +msgid "" +"The path for service {name!s} is {path!s}, which does not " +"exist." +msgstr "" +"Đường dẫn cho dịch vụ {name!s} là {path!s}, nhưng không tồn " +"tại." + +#: src/modules/plymouthcfg/main.py:27 +msgid "Configure Plymouth theme" +msgstr "Cấu hình giao diện Plymouth" + +#: src/modules/packages/main.py:50 src/modules/packages/main.py:59 +#: src/modules/packages/main.py:69 +msgid "Install packages." +msgstr "Đang cài đặt các gói ứng dụng." + +#: src/modules/packages/main.py:57 +#, python-format +msgid "Processing packages (%(count)d / %(total)d)" +msgstr "Đang xử lý gói (%(count)d / %(total)d)" + +#: src/modules/packages/main.py:62 +#, python-format +msgid "Installing one package." +msgid_plural "Installing %(num)d packages." +msgstr[0] "Đang cài đặt %(num)d gói ứng dụng." + +#: src/modules/packages/main.py:65 +#, python-format +msgid "Removing one package." +msgid_plural "Removing %(num)d packages." +msgstr[0] "Đang gỡ bỏ %(num)d gói ứng dụng." + +#: src/modules/bootloader/main.py:42 +msgid "Install bootloader." +msgstr "Đang cài đặt bộ khởi động." + +#: src/modules/hwclock/main.py:26 +msgid "Setting hardware clock." +msgstr "Đang thiết lập đồng hồ máy tính." + +#: src/modules/mkinitfs/main.py:27 +msgid "Creating initramfs with mkinitfs." +msgstr "Đang tạo initramfs bằng mkinitfs." + +#: src/modules/mkinitfs/main.py:49 +msgid "Failed to run mkinitfs on the target" +msgstr "Chạy mkinitfs thất bại ở hệ thống đích" + +#: src/modules/mkinitfs/main.py:50 src/modules/dracut/main.py:50 +msgid "The exit code was {}" +msgstr "Mã lỗi trả về là {}" + +#: src/modules/dracut/main.py:27 +msgid "Creating initramfs with dracut." +msgstr "Đang tạo initramfs bằng dracut." + +#: src/modules/dracut/main.py:49 +msgid "Failed to run dracut on the target" +msgstr "Chạy dracut thất bại ở hệ thống đích" + +#: src/modules/initramfscfg/main.py:32 +msgid "Configuring initramfs." +msgstr "Đang cấu hình initramfs." + +#: src/modules/openrcdmcryptcfg/main.py:25 +msgid "Configuring OpenRC dmcrypt service." +msgstr "Đang cấu hình dịch vụ OpenRC dmcrypt." + +#: src/modules/fstab/main.py:29 +msgid "Writing fstab." +msgstr "Đang viết vào fstab." + +#: src/modules/dummypython/main.py:35 +msgid "Dummy python job." +msgstr "Ví dụ công việc python." + +#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93 +#: src/modules/dummypython/main.py:94 +msgid "Dummy python step {}" +msgstr "Ví dụ python bước {}" + +#: src/modules/localecfg/main.py:30 +msgid "Configuring locales." +msgstr "Đang cấu hình ngôn ngữ." + +#: src/modules/networkcfg/main.py:28 +msgid "Saving network configuration." +msgstr "Đang lưu cấu hình mạng." diff --git a/lang/python/zh_TW/LC_MESSAGES/python.po b/lang/python/zh_TW/LC_MESSAGES/python.po index 92457638c..4196c3d0b 100644 --- a/lang/python/zh_TW/LC_MESSAGES/python.po +++ b/lang/python/zh_TW/LC_MESSAGES/python.po @@ -199,7 +199,7 @@ msgstr "未在顯示管理器模組中選取顯示管理器。" msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." -msgstr "" +msgstr "顯示管理器清單為空或在 globalstorage 與 displaymanager.conf 中皆未定義。" #: src/modules/displaymanager/main.py:977 msgid "Display manager configuration was incomplete" diff --git a/lang/tz_vi.ts b/lang/tz_vi.ts new file mode 100644 index 000000000..b7149efa9 --- /dev/null +++ b/lang/tz_vi.ts @@ -0,0 +1,2617 @@ + + + + + QObject + + + Africa + tz_regions + Châu phi + + + + America + tz_regions + Châu Mỹ + + + + Antarctica + tz_regions + Nam Cực + + + + Arctic + tz_regions + Bắc cực + + + + Asia + tz_regions + Châu Á + + + + Atlantic + tz_regions + Đại Tây Dương + + + + Australia + tz_regions + Châu Úc + + + + Europe + tz_regions + Châu Âu + + + + Indian + tz_regions + Ấn Độ + + + + Pacific + tz_regions + Thái Bình Dương + + + + Abidjan + tz_names + Abidjan + + + + Accra + tz_names + Accra + + + + Adak + tz_names + Adak + + + + Addis Ababa + tz_names + A-đi A-ba-ba + + + + Adelaide + tz_names + Adelaide + + + + Aden + tz_names + Aden + + + + Algiers + tz_names + Algiers + + + + Almaty + tz_names + Almaty + + + + Amman + tz_names + Amman + + + + Amsterdam + tz_names + Am-xtéc-đam + + + + Anadyr + tz_names + Anadyr + + + + Anchorage + tz_names + Anchorage + + + + Andorra + tz_names + Andorra + + + + Anguilla + tz_names + An-gui-la + + + + Antananarivo + tz_names + An-ta-na-na-ri-vô + + + + Antigua + tz_names + Antigua + + + + Apia + tz_names + A-pi-a + + + + Aqtau + tz_names + Aqtau + + + + Aqtobe + tz_names + Aqtobe + + + + Araguaina + tz_names + Araguaina + + + + Argentina/Buenos Aires + tz_names + Ác-hen-ti-na/Buenos Aires + + + + Argentina/Catamarca + tz_names + Ác-hen-ti-na/Catamarca + + + + Argentina/Cordoba + tz_names + Ác-hen-ti-na/Cordoba + + + + Argentina/Jujuy + tz_names + Ác-hen-ti-na/Jujuy + + + + Argentina/La Rioja + tz_names + Ác-hen-ti-na/La Rioja + + + + Argentina/Mendoza + tz_names + Ác-hen-ti-na/Mendoza + + + + Argentina/Rio Gallegos + tz_names + Ác-hen-ti-na/Rio Gallegos + + + + Argentina/Salta + tz_names + Ác-hen-ti-na/Salta + + + + Argentina/San Juan + tz_names + Ác-hen-ti-na/San Juan + + + + Argentina/San Luis + tz_names + Ác-hen-ti-na/San Luis + + + + Argentina/Tucuman + tz_names + Ác-hen-ti-na/Tucuman + + + + Argentina/Ushuaia + tz_names + Ác-hen-ti-na/Ushuaia + + + + Aruba + tz_names + A-ru-ba + + + + Ashgabat + tz_names + A-sơ-kha0bast + + + + Asmara + tz_names + Át-ma-ra + + + + Astrakhan + tz_names + Astrakhan + + + + Asuncion + tz_names + A-sun-sân + + + + Athens + tz_names + A-ten + + + + Atikokan + tz_names + Atikokan + + + + Atyrau + tz_names + Atyrau + + + + Auckland + tz_names + Auckland + + + + Azores + tz_names + Azores + + + + Baghdad + tz_names + Bát-đa + + + + Bahia + tz_names + Bahia + + + + Bahia Banderas + tz_names + Bahia Banderas + + + + Bahrain + tz_names + Ba-ranh + + + + Baku + tz_names + Ba-cu + + + + Bamako + tz_names + Bamako + + + + Bangkok + tz_names + Băng Cốc + + + + Bangui + tz_names + Ban-gui + + + + Banjul + tz_names + Ban-giun + + + + Barbados + tz_names + Bác-ba-đốt + + + + Barnaul + tz_names + Barnaul + + + + Beirut + tz_names + Bê-rút + + + + Belem + tz_names + Belem + + + + Belgrade + tz_names + Bê-ô-grát + + + + Belize + tz_names + Bê-li-xê + + + + Berlin + tz_names + Béc Lin + + + + Bermuda + tz_names + Béc-mu-đa + + + + Bishkek + tz_names + Bi-skec + + + + Bissau + tz_names + Bit-xao + + + + Blanc-Sablon + tz_names + Blanc-Sablon + + + + Blantyre + tz_names + Blantyre + + + + Boa Vista + tz_names + Boa Vista + + + + Bogota + tz_names + Bô-gô-ta + + + + Boise + tz_names + Boise + + + + Bougainville + tz_names + Bougainville + + + + Bratislava + tz_names + Bra-tít-xla-va + + + + Brazzaville + tz_names + Brazzaville + + + + Brisbane + tz_names + Brisbane + + + + Broken Hill + tz_names + Đồi Broken + + + + Brunei + tz_names + Bru-nây + + + + Brussels + tz_names + Brúc-xen + + + + Bucharest + tz_names + Bu-ca-rét + + + + Budapest + tz_names + Bu-đa-pét + + + + Bujumbura + tz_names + Bu-gium-bu-ra + + + + Busingen + tz_names + Busingen + + + + Cairo + tz_names + Cai Rô + + + + Cambridge Bay + tz_names + Vịnh Cambridge + + + + Campo Grande + tz_names + Campo Grande + + + + Canary + tz_names + Canary + + + + Cancun + tz_names + Cancun + + + + Cape Verde + tz_names + Cáp-ve + + + + Caracas + tz_names + Ca-ra-cát + + + + Casablanca + tz_names + Casablanca + + + + Casey + tz_names + Casey + + + + Cayenne + tz_names + Cayenne + + + + Cayman + tz_names + Quần đảo Cay-man + + + + Ceuta + tz_names + Ceuta + + + + Chagos + tz_names + Chagos + + + + Chatham + tz_names + Chatham + + + + Chicago + tz_names + Chi Ca Gô + + + + Chihuahua + tz_names + Chihuahua + + + + Chisinau + tz_names + Ki-si-nhốp + + + + Chita + tz_names + Chita + + + + Choibalsan + tz_names + Choibalsan + + + + Christmas + tz_names + Christmas + + + + Chuuk + tz_names + Chuuk + + + + Cocos + tz_names + Cocos + + + + Colombo + tz_names + Cô Lôm Bô + + + + Comoro + tz_names + (Liên bang) Cô-mo + + + + Conakry + tz_names + Cô-na-cri + + + + Copenhagen + tz_names + Cô-pen-ha-gen + + + + Costa Rica + tz_names + Cốt-xta-ri-ca + + + + Creston + tz_names + Creston + + + + Cuiaba + tz_names + Cuiaba + + + + Curacao + tz_names + Cu-ra-xao + + + + Currie + tz_names + Currie + + + + Dakar + tz_names + Dakar + + + + Damascus + tz_names + Đa-mát + + + + Danmarkshavn + tz_names + Danmarkshavn + + + + Dar es Salaam + tz_names + Dar es Salaam + + + + Darwin + tz_names + Darwin + + + + Davis + tz_names + Davis + + + + Dawson + tz_names + Dawson + + + + Dawson Creek + tz_names + Dawson Creek + + + + Denver + tz_names + Denver + + + + Detroit + tz_names + Detroit + + + + Dhaka + tz_names + Đắc-ca + + + + Dili + tz_names + Đi-li + + + + Djibouti + tz_names + Cộng hòa Gi-bu-ti + + + + Dominica + tz_names + Đô-mi-ni-ca-na + + + + Douala + tz_names + Douala + + + + Dubai + tz_names + Đu Bai + + + + Dublin + tz_names + Đu-blin + + + + DumontDUrville + tz_names + DumontDUrville + + + + Dushanbe + tz_names + Đu-san-be + + + + Easter + tz_names + Đảo Phục Sinh + + + + Edmonton + tz_names + Edmonton + + + + Efate + tz_names + Efate + + + + Eirunepe + tz_names + Eirunepe + + + + El Aaiun + tz_names + El Aaiun + + + + El Salvador + tz_names + En Xan-va-đo + + + + Enderbury + tz_names + Đảo Enderbury + + + + Eucla + tz_names + Eucla + + + + Fakaofo + tz_names + Fakaofo + + + + Famagusta + tz_names + Famagusta + + + + Faroe + tz_names + Quần đảo Fa-rô + + + + Fiji + tz_names + Phi-gi + + + + Fort Nelson + tz_names + Fort Nelson + + + + Fortaleza + tz_names + Fortaleza + + + + Freetown + tz_names + Phritao + + + + Funafuti + tz_names + Funafuti + + + + Gaborone + tz_names + Ga-bô-rô-nê + + + + Galapagos + tz_names + Quần đảo Galapagos + + + + Gambier + tz_names + Gambier + + + + Gaza + tz_names + Dải Gaza + + + + Gibraltar + tz_names + Gibraltar + + + + Glace Bay + tz_names + Vịnh Glace + + + + Godthab + tz_names + Nu-úc + + + + Goose Bay + tz_names + Vịnh Goose + + + + Grand Turk + tz_names + Đảo Grand Turk + + + + Grenada + tz_names + Grê-na-đa + + + + Guadalcanal + tz_names + Guadalcanal + + + + Guadeloupe + tz_names + Goa-đê-lốp + + + + Guam + tz_names + Guam + + + + Guatemala + tz_names + Goa-tê-ma-la + + + + Guayaquil + tz_names + Guayaquil + + + + Guernsey + tz_names + Guernsey + + + + Guyana + tz_names + Guy-a-na + + + + Halifax + tz_names + Halifa + + + + Harare + tz_names + Ha-ra-rê + + + + Havana + tz_names + Ha Va Na + + + + Hebron + tz_names + Hebron + + + + Helsinki + tz_names + Hen-sin-ki + + + + Hermosillo + tz_names + Hermosillo + + + + Ho Chi Minh + tz_names + Hồ Chí Minh + + + + Hobart + tz_names + Hobart + + + + Hong Kong + tz_names + Hồng Công + + + + Honolulu + tz_names + Honolulu + + + + Hovd + tz_names + Khovd + + + + Indiana/Indianapolis + tz_names + Indiana/Indianapolis + + + + Indiana/Knox + tz_names + Indiana/Knox + + + + Indiana/Marengo + tz_names + Indiana/Marengo + + + + Indiana/Petersburg + tz_names + Indiana/Petersburg + + + + Indiana/Tell City + tz_names + Indiana/Tell City + + + + Indiana/Vevay + tz_names + Indiana/Vevay + + + + Indiana/Vincennes + tz_names + Indiana/Vincennes + + + + Indiana/Winamac + tz_names + Indiana/Winamac + + + + Inuvik + tz_names + Inuvik + + + + Iqaluit + tz_names + Iqaluit + + + + Irkutsk + tz_names + Irkutsk + + + + Isle of Man + tz_names + Đảo Man + + + + Istanbul + tz_names + Istanbul + + + + Jakarta + tz_names + Gia Các Ta + + + + Jamaica + tz_names + Gia-mai-ca + + + + Jayapura + tz_names + Jayapura + + + + Jersey + tz_names + Jersey + + + + Jerusalem + tz_names + Giê-ru-xa-lem + + + + Johannesburg + tz_names + Johannesburg + + + + Juba + tz_names + Juba + + + + Juneau + tz_names + Juneau + + + + Kabul + tz_names + Ka-bun + + + + Kaliningrad + tz_names + Kaliningrad + + + + Kamchatka + tz_names + Bán đảo Kamchatka + + + + Kampala + tz_names + Campala + + + + Karachi + tz_names + Karachi + + + + Kathmandu + tz_names + Cát-man-đu + + + + Kentucky/Louisville + tz_names + Ken túc ky/Louisville + + + + Kentucky/Monticello + tz_names + Ken túc ky/Monticello + + + + Kerguelen + tz_names + Đảo Kerguelen + + + + Khandyga + tz_names + Khandyga + + + + Khartoum + tz_names + Khác-tum + + + + Kiev + tz_names + Kyiv + + + + Kigali + tz_names + Ki-ga-li + + + + Kinshasa + tz_names + Kin-xa-sa + + + + Kiritimati + tz_names + Kiritimati + + + + Kirov + tz_names + Kirov + + + + Kolkata + tz_names + Kolkata + + + + Kosrae + tz_names + Kosrae + + + + Kralendijk + tz_names + Kralendijk + + + + Krasnoyarsk + tz_names + Krasnoyarsk + + + + Kuala Lumpur + tz_names + Kuala Lam Pơ + + + + Kuching + tz_names + Kuching + + + + Kuwait + tz_names + Kuwait + + + + Kwajalein + tz_names + Kwajalein + + + + La Paz + tz_names + La Pa-xơ + + + + Lagos + tz_names + Lagos + + + + Libreville + tz_names + Li-brơ-vin + + + + Lima + tz_names + Lima + + + + Lindeman + tz_names + Hồ Lindeman + + + + Lisbon + tz_names + Lít Bon + + + + Ljubljana + tz_names + Liu-bli-an-na + + + + Lome + tz_names + Lô-mê + + + + London + tz_names + Luân Đôn + + + + Longyearbyen + tz_names + Longyearbyen + + + + Lord Howe + tz_names + Đảo Lord Howe + + + + Los Angeles + tz_names + Lốt Ăng Giơ Lét + + + + Lower Princes + tz_names + Lower Princes + + + + Luanda + tz_names + Lu-an-đa + + + + Lubumbashi + tz_names + Lubumbashi + + + + Lusaka + tz_names + Lu-xa-ca + + + + Luxembourg + tz_names + Lúc-xăm-bua + + + + Macau + tz_names + Ma Cao + + + + Maceio + tz_names + Maceio + + + + Macquarie + tz_names + Macquarie + + + + Madeira + tz_names + Madeira + + + + Madrid + tz_names + Ma Rích + + + + Magadan + tz_names + Magadan + + + + Mahe + tz_names + Mahe + + + + Majuro + tz_names + Majuro + + + + Makassar + tz_names + Makassar + + + + Malabo + tz_names + Malabo + + + + Maldives + tz_names + Man-đi-vơ + + + + Malta + tz_names + Man-Man-tata + + + + Managua + tz_names + Ma-na-goa + + + + Manaus + tz_names + Manaus + + + + Manila + tz_names + Manila + + + + Maputo + tz_names + Maputo + + + + Mariehamn + tz_names + Mariehamn + + + + Marigot + tz_names + Marigot + + + + Marquesas + tz_names + Quần đảo Marquesas + + + + Martinique + tz_names + Martinique + + + + Maseru + tz_names + Ma-xê-ru + + + + Matamoros + tz_names + Matamoros + + + + Mauritius + tz_names + Mô-ri-xơ + + + + Mawson + tz_names + Mawson + + + + Mayotte + tz_names + Mayotte + + + + Mazatlan + tz_names + Mazatlan + + + + Mbabane + tz_names + Mbabane + + + + McMurdo + tz_names + McMurdo + + + + Melbourne + tz_names + Melbourne + + + + Menominee + tz_names + Menominee + + + + Merida + tz_names + Merida + + + + Metlakatla + tz_names + Metlakatla + + + + Mexico City + tz_names + Thành phố Mê Xi Cô + + + + Midway + tz_names + Midway + + + + Minsk + tz_names + Min-xcơ + + + + Miquelon + tz_names + Mi-kê-lân + + + + Mogadishu + tz_names + Mô-ga-đi-su + + + + Monaco + tz_names + Mô-na-cô + + + + Moncton + tz_names + Moncton + + + + Monrovia + tz_names + Monrovia + + + + Monterrey + tz_names + Monterrey + + + + Montevideo + tz_names + Mông-tơ-vi-di-ô + + + + Montserrat + tz_names + Montserrat + + + + Moscow + tz_names + Mát Cơ Va + + + + Muscat + tz_names + Mu Cát + + + + Nairobi + tz_names + Nai-rô-bi + + + + Nassau + tz_names + Nát-xô + + + + Nauru + tz_names + Na-u-ru + + + + Ndjamena + tz_names + Gia-mê-na + + + + New York + tz_names + Nữu Ước + + + + Niamey + tz_names + Ni-a-mây + + + + Nicosia + tz_names + Ni-cô-xi-a + + + + Nipigon + tz_names + Nipigon + + + + Niue + tz_names + Ni-u-ê + + + + Nome + tz_names + Nome + + + + Norfolk + tz_names + Norfolk + + + + Noronha + tz_names + Noronha + + + + North Dakota/Beulah + tz_names + Bắc Dakota/Beulah + + + + North Dakota/Center + tz_names + Bắc Dakota/Center + + + + North Dakota/New Salem + tz_names + Bắc Dakota/New Salem + + + + Nouakchott + tz_names + Nu-ác-sốt + + + + Noumea + tz_names + No-mi + + + + Novokuznetsk + tz_names + Novokuznetsk + + + + Novosibirsk + tz_names + Novosibirsk + + + + Ojinaga + tz_names + Ojinaga + + + + Omsk + tz_names + Omsk + + + + Oral + tz_names + Oral + + + + Oslo + tz_names + Ốt-xlô + + + + Ouagadougou + tz_names + U-a-ga-đu-gu + + + + Pago Pago + tz_names + Pago Pago + + + + Palau + tz_names + Pa-lau + + + + Palmer + tz_names + Palmer + + + + Panama + tz_names + Pa-na-ma + + + + Pangnirtung + tz_names + Pangnirtung + + + + Paramaribo + tz_names + Pa-ra-ma-ri-bô + + + + Paris + tz_names + Pa Ri + + + + Perth + tz_names + Perth + + + + Phnom Penh + tz_names + Phnôm Pênh + + + + Phoenix + tz_names + Phoenix + + + + Pitcairn + tz_names + Quần đảo Pít-cơn + + + + Podgorica + tz_names + Pốt-gô-ri-xa + + + + Pohnpei + tz_names + Pohnpei + + + + Pontianak + tz_names + Pontianak + + + + Port Moresby + tz_names + Cảng Moresby + + + + Port of Spain + tz_names + Cảng Tây Ban Nha + + + + Port-au-Prince + tz_names + Cảng au Prince + + + + Porto Velho + tz_names + Cảng Velho + + + + Porto-Novo + tz_names + Cảng-Novo + + + + Prague + tz_names + Praha + + + + Puerto Rico + tz_names + Cảng Rico + + + + Punta Arenas + tz_names + Đấu trường Punta + + + + Pyongyang + tz_names + Bình Nhưỡng + + + + Qatar + tz_names + Ca-ta + + + + Qostanay + tz_names + Kostanay + + + + Qyzylorda + tz_names + Kyzylorda + + + + Rainy River + tz_names + Rainy River + + + + Rankin Inlet + tz_names + Rankin Inlet + + + + Rarotonga + tz_names + Rarotonga + + + + Recife + tz_names + Recife + + + + Regina + tz_names + Regina + + + + Resolute + tz_names + Resolute + + + + Reunion + tz_names + Rê-u-niên + + + + Reykjavik + tz_names + Rây-ki-a-vích + + + + Riga + tz_names + Ri-ga + + + + Rio Branco + tz_names + Rio Branco + + + + Riyadh + tz_names + Ri-át + + + + Rome + tz_names + Rô Ma + + + + Rothera + tz_names + Rothera + + + + Saipan + tz_names + Saipan + + + + Sakhalin + tz_names + Sakhalin + + + + Samara + tz_names + Samara + + + + Samarkand + tz_names + Samarkand + + + + San Marino + tz_names + San Marino + + + + Santarem + tz_names + Santarem + + + + Santiago + tz_names + Santiago + + + + Santo Domingo + tz_names + Xan-tô Đô-min-gô + + + + Sao Paulo + tz_names + Sao Paolo + + + + Sao Tome + tz_names + Sao Tô-mê + + + + Sarajevo + tz_names + Xa-ra-ê-vô + + + + Saratov + tz_names + Saratov + + + + Scoresbysund + tz_names + Scoresby Sund + + + + Seoul + tz_names + Xê un + + + + Shanghai + tz_names + Thượng Hải + + + + Simferopol + tz_names + Simferopol + + + + Singapore + tz_names + Singapo + + + + Sitka + tz_names + Sitka + + + + Skopje + tz_names + Xcốp-pi-ê + + + + Sofia + tz_names + Sofia + + + + South Georgia + tz_names + Nam Georgia + + + + Srednekolymsk + tz_names + Srednekolymsk + + + + St Barthelemy + tz_names + St Barthelemy + + + + St Helena + tz_names + St Helena + + + + St Johns + tz_names + St Johns + + + + St Kitts + tz_names + St Kitts + + + + St Lucia + tz_names + St Lucia + + + + St Thomas + tz_names + St Thomas + + + + St Vincent + tz_names + St Vincent + + + + Stanley + tz_names + Stanley + + + + Stockholm + tz_names + Xtốc-khôm + + + + Swift Current + tz_names + Swift Current + + + + Sydney + tz_names + Xít ni + + + + Syowa + tz_names + Syowa + + + + Tahiti + tz_names + Tahiti + + + + Taipei + tz_names + Đài Bắc + + + + Tallinn + tz_names + Ta-lin + + + + Tarawa + tz_names + Tarawa + + + + Tashkent + tz_names + Ta-sơ-ken + + + + Tbilisi + tz_names + Tbi-li-xi + + + + Tegucigalpa + tz_names + Te-gu-xi-gan-pa + + + + Tehran + tz_names + Tê-hê-ran + + + + Thimphu + tz_names + Thim-bu + + + + Thule + tz_names + Thule + + + + Thunder Bay + tz_names + Vịnh Thunder + + + + Tijuana + tz_names + Tijuana + + + + Tirane + tz_names + Ti-ra-na + + + + Tokyo + tz_names + Tô Ky Ôs + + + + Tomsk + tz_names + Tomsk + + + + Tongatapu + tz_names + Tongatapu + + + + Toronto + tz_names + Tô Rôn Tô + + + + Tortola + tz_names + Tortola + + + + Tripoli + tz_names + Tri Pô Li + + + + Troll + tz_names + Troll + + + + Tunis + tz_names + Tuy-nít + + + + Ulaanbaatar + tz_names + Ulan Bato + + + + Ulyanovsk + tz_names + Ulyanovsk + + + + Urumqi + tz_names + Urumqi + + + + Ust-Nera + tz_names + Ust-Nera + + + + Uzhgorod + tz_names + Uzhgorod + + + + Vaduz + tz_names + Vaduz + + + + Vancouver + tz_names + Van Cô Vơ + + + + Vatican + tz_names + Va Ti Can + + + + Vienna + tz_names + Viên + + + + Vientiane + tz_names + Viêng Chăn + + + + Vilnius + tz_names + Vin-ni-út + + + + Vladivostok + tz_names + Vladivostok + + + + Volgograd + tz_names + Volgograd + + + + Vostok + tz_names + Vostok + + + + Wake + tz_names + Wake + + + + Wallis + tz_names + Wa Li + + + + Warsaw + tz_names + Vác-sa-va + + + + Whitehorse + tz_names + Whitehorse + + + + Windhoek + tz_names + Windhoek + + + + Winnipeg + tz_names + Winnipeg + + + + Yakutat + tz_names + Yakutat + + + + Yakutsk + tz_names + Yakutsk + + + + Yangon + tz_names + Ragoon + + + + Yekaterinburg + tz_names + Yekaterinburg + + + + Yellowknife + tz_names + Yellowknife + + + + Yerevan + tz_names + Ê-rê-van + + + + Zagreb + tz_names + Da-gờ-rép + + + + Zaporozhye + tz_names + Zaporizhia + + + + Zurich + tz_names + Zurich + + + diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index 94abb9f54..abea69a26 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -42,7 +42,7 @@ set( calamares_i18n_qrc_content "" ) # calamares and qt language files foreach( lang ${CALAMARES_TRANSLATION_LANGUAGES} ) - foreach( tlsource "calamares_${lang}" "tz_${lang}" ) + foreach( tlsource "calamares_${lang}" "tz_${lang}" "kb_${lang}" ) if( EXISTS "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" ) set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}${tlsource}.qm\n" ) list( APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" ) diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp index 0960da10a..a141317e0 100644 --- a/src/calamares/CalamaresWindow.cpp +++ b/src/calamares/CalamaresWindow.cpp @@ -271,7 +271,7 @@ flavoredWidget( Calamares::Branding::PanelFlavor flavor, case Calamares::Branding::PanelFlavor::None: return nullptr; } - NOTREACHED return nullptr; // All enum values handled above + __builtin_unreachable(); } /** @brief Adds widgets to @p layout if they belong on this @p side diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index b1e40c3ae..3964eb3e6 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -86,9 +86,6 @@ if( WITH_PYTHON ) PythonJob.cpp PythonJobApi.cpp ) - set_source_files_properties( PythonJob.cpp - PROPERTIES COMPILE_FLAGS "${SUPPRESS_BOOST_WARNINGS}" - ) include_directories(${PYTHON_INCLUDE_DIRS}) link_directories(${PYTHON_LIBRARIES}) @@ -148,8 +145,8 @@ calamares_automoc( calamares ) target_link_libraries( calamares LINK_PRIVATE ${OPTIONAL_PRIVATE_LIBRARIES} - yamlcpp LINK_PUBLIC + yamlcpp Qt5::Core KF5::CoreAddons ${OPTIONAL_PUBLIC_LIBRARIES} diff --git a/src/libcalamares/JobQueue.cpp b/src/libcalamares/JobQueue.cpp index 1637f0719..b66be7ebe 100644 --- a/src/libcalamares/JobQueue.cpp +++ b/src/libcalamares/JobQueue.cpp @@ -249,6 +249,7 @@ JobQueue::~JobQueue() } delete m_storage; + s_instance = nullptr; } diff --git a/src/libcalamares/PythonJob.cpp b/src/libcalamares/PythonJob.cpp index cd066b8bd..6944f38e5 100644 --- a/src/libcalamares/PythonJob.cpp +++ b/src/libcalamares/PythonJob.cpp @@ -284,7 +284,7 @@ PythonJob::exec() return JobResult::error( message, description ); } } - catch ( bp::error_already_set ) + catch ( bp::error_already_set& ) { QString msg; if ( PyErr_Occurred() ) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 648ea69f4..8ef72d99b 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -101,7 +101,7 @@ create_interface( Handler::Type t, const QString& selector ) case Handler::Type::Fixed: return std::make_unique< GeoIPFixed >( selector ); } - NOTREACHED return nullptr; + __builtin_unreachable(); } static RegionZonePair diff --git a/src/libcalamares/geoip/test_geoip.cpp b/src/libcalamares/geoip/test_geoip.cpp index fd50cecff..0e14dcf91 100644 --- a/src/libcalamares/geoip/test_geoip.cpp +++ b/src/libcalamares/geoip/test_geoip.cpp @@ -37,7 +37,7 @@ main( int argc, char** argv ) QString format( argv[ 1 ] ); QString selector = argc == 3 ? QString( argv[ 2 ] ) : QString(); - Logger::setupLogLevel(Logger::LOGVERBOSE); + Logger::setupLogLevel( Logger::LOGVERBOSE ); cDebug() << "Doing GeoIP interpretation with format=" << format << "selector=" << selector; Interface* handler = nullptr; diff --git a/src/libcalamares/modulesystem/Module.cpp b/src/libcalamares/modulesystem/Module.cpp index 94888f240..ff0b20f78 100644 --- a/src/libcalamares/modulesystem/Module.cpp +++ b/src/libcalamares/modulesystem/Module.cpp @@ -86,7 +86,8 @@ moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, c return paths; } -void Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Exception +void +Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Exception { QStringList configCandidates = moduleConfigurationCandidates( Settings::instance()->debugMode(), name(), configFileName ); diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp index 9dfab0c8f..6a7e0a5b4 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -85,16 +85,11 @@ void RequirementsModel::describe() const { cDebug() << "Requirements model has" << m_requirements.count() << "items"; - bool acceptable = true; int count = 0; for ( const auto& r : m_requirements ) { cDebug() << Logger::SubEntry << "requirement" << count << r.name << "satisfied?" << r.satisfied << "mandatory?" << r.mandatory; - if ( r.mandatory && !r.satisfied ) - { - acceptable = false; - } ++count; } } diff --git a/src/libcalamares/partition/KPMHelper.h b/src/libcalamares/partition/KPMHelper.h new file mode 100644 index 000000000..f6007b119 --- /dev/null +++ b/src/libcalamares/partition/KPMHelper.h @@ -0,0 +1,43 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +/* + * KPMCore header file inclusion. + * + * Includes the system KPMCore headers without warnings (by switching off + * the expected warnings). + */ +#ifndef PARTITION_KPMHELPER_H +#define PARTITION_KPMHELPER_H + +// The kpmcore headers are not C++17 warning-proof, especially +// with picky compilers like Clang 10. Since we use Clang for the +// find-all-the-warnings case, switch those warnings off for +// the we-can't-change-them system headers. +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wsuggest-destructor-override" +#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif diff --git a/src/libcalamares/partition/PartitionQuery.cpp b/src/libcalamares/partition/PartitionQuery.cpp index beba6b9bc..4c9c1549d 100644 --- a/src/libcalamares/partition/PartitionQuery.cpp +++ b/src/libcalamares/partition/PartitionQuery.cpp @@ -27,14 +27,14 @@ using ::Device; using ::Partition; bool -isPartitionFreeSpace( Partition* partition ) +isPartitionFreeSpace( const Partition* partition ) { return partition->roles().has( PartitionRole::Unallocated ); } bool -isPartitionNew( Partition* partition ) +isPartitionNew( const Partition* partition ) { #if defined( WITH_KPMCORE4API ) constexpr auto NewState = Partition::State::New; @@ -67,11 +67,15 @@ findPartitionByPath( const QList< Device* >& devices, const QString& path ) } for ( auto device : devices ) + { for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) + { if ( ( *it )->partitionPath() == path.simplified() ) { return *it; } + } + } return nullptr; } @@ -81,11 +85,15 @@ findPartitions( const QList< Device* >& devices, std::function< bool( Partition* { QList< Partition* > results; for ( auto device : devices ) + { for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) + { if ( criterionFunction( *it ) ) { results.append( *it ); } + } + } return results; } diff --git a/src/libcalamares/partition/PartitionQuery.h b/src/libcalamares/partition/PartitionQuery.h index 817966d35..9ef5f41f6 100644 --- a/src/libcalamares/partition/PartitionQuery.h +++ b/src/libcalamares/partition/PartitionQuery.h @@ -34,14 +34,14 @@ using ::Device; using ::Partition; /** @brief Is this a free-space area? */ -bool isPartitionFreeSpace( Partition* ); +bool isPartitionFreeSpace( const Partition* ); /** @brief Is this partition newly-to-be-created? * * Returns true if the partition is planned to be created by the installer as * opposed to already existing on the disk. */ -bool isPartitionNew( Partition* ); +bool isPartitionNew( const Partition* ); /** * Iterates on all devices and return the first partition which is (already) diff --git a/src/libcalamares/partition/PartitionSize.cpp b/src/libcalamares/partition/PartitionSize.cpp index d09cc6064..ddd3be2ef 100644 --- a/src/libcalamares/partition/PartitionSize.cpp +++ b/src/libcalamares/partition/PartitionSize.cpp @@ -139,9 +139,7 @@ PartitionSize::toBytes( qint64 totalSectors, qint64 sectorSize ) const case SizeUnit::GiB: return toBytes(); } - - // notreached - return -1; + __builtin_unreachable(); } qint64 @@ -178,9 +176,7 @@ PartitionSize::toBytes( qint64 totalBytes ) const case SizeUnit::GiB: return toBytes(); } - - // notreached - return -1; + __builtin_unreachable(); } qint64 @@ -211,7 +207,7 @@ PartitionSize::toBytes() const case SizeUnit::GiB: return CalamaresUtils::GiBtoBytes( static_cast< unsigned long long >( value() ) ); } - NOTREACHED return -1; + __builtin_unreachable(); } bool @@ -237,7 +233,7 @@ PartitionSize::operator<( const PartitionSize& other ) const case SizeUnit::GiB: return ( toBytes() < other.toBytes() ); } - NOTREACHED return false; + __builtin_unreachable(); } bool @@ -263,7 +259,7 @@ PartitionSize::operator>( const PartitionSize& other ) const case SizeUnit::GiB: return ( toBytes() > other.toBytes() ); } - NOTREACHED return false; + __builtin_unreachable(); } bool @@ -289,7 +285,7 @@ PartitionSize::operator==( const PartitionSize& other ) const case SizeUnit::GiB: return ( toBytes() == other.toBytes() ); } - NOTREACHED return false; + __builtin_unreachable(); } } // namespace Partition diff --git a/src/libcalamares/utils/RAII.h b/src/libcalamares/utils/RAII.h index d6f8fe94d..1cbead4a2 100644 --- a/src/libcalamares/utils/RAII.h +++ b/src/libcalamares/utils/RAII.h @@ -16,20 +16,28 @@ #include -/// @brief Convenience to zero out and deleteLater of any QObject-derived-class +/** @brief Convenience to zero out and deleteLater of any QObject-derived-class + * + * If, before destruction, preserve is set to @c true, then + * the object is "preserved", and not deleted at all. + */ template < typename T > struct cqDeleter { T*& p; + bool preserve = false; ~cqDeleter() { static_assert( std::is_base_of< QObject, T >::value, "Not a QObject-class" ); - if ( p ) + if ( !preserve ) { - p->deleteLater(); + if ( p ) + { + p->deleteLater(); + } + p = nullptr; } - p = nullptr; } }; diff --git a/src/libcalamares/utils/Retranslator.cpp b/src/libcalamares/utils/Retranslator.cpp index a03ae9a3b..46bafab85 100644 --- a/src/libcalamares/utils/Retranslator.cpp +++ b/src/libcalamares/utils/Retranslator.cpp @@ -168,17 +168,17 @@ TZLoader::tryLoad( QTranslator* translator ) static void loadSingletonTranslator( TranslationLoader&& loader, QTranslator*& translator_p ) { - QTranslator* translator = new QTranslator(); - loader.tryLoad( translator ); - - if ( translator_p ) + if ( !translator_p ) { - QCoreApplication::removeTranslator( translator_p ); - delete translator_p; + QTranslator* translator = new QTranslator(); + loader.tryLoad( translator ); + QCoreApplication::installTranslator( translator ); + translator_p = translator; + } + else + { + loader.tryLoad( translator_p ); } - - QCoreApplication::installTranslator( translator ); - translator_p = translator; } namespace CalamaresUtils @@ -193,10 +193,9 @@ installTranslator( const QLocale& locale, const QString& brandingTranslationsPre { loadSingletonTranslator( BrandingLoader( locale, brandingTranslationsPrefix ), s_brandingTranslator ); loadSingletonTranslator( TZLoader( locale ), s_tztranslator ); + loadSingletonTranslator( CalamaresLoader( locale ), s_translator ); - CalamaresLoader l( locale ); // because we want the extracted localeName - loadSingletonTranslator( std::move( l ), s_translator ); - s_translatorLocaleName = l.m_localeName; + s_translatorLocaleName = CalamaresLoader::mungeLocaleName( locale ); } @@ -206,6 +205,12 @@ translatorLocaleName() return s_translatorLocaleName; } +bool +loadTranslator( const QLocale& locale, const QString& prefix, QTranslator* translator ) +{ + return ::tryLoad( translator, prefix, locale.name() ); +} + Retranslator* Retranslator::retranslatorFor( QObject* parent ) { diff --git a/src/libcalamares/utils/Retranslator.h b/src/libcalamares/utils/Retranslator.h index 476c0b184..df38fa4d8 100644 --- a/src/libcalamares/utils/Retranslator.h +++ b/src/libcalamares/utils/Retranslator.h @@ -21,6 +21,7 @@ class QEvent; class QLocale; +class QTranslator; namespace CalamaresUtils { @@ -31,8 +32,29 @@ namespace CalamaresUtils */ DLLEXPORT void installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix ); +/** @brief The name of the (locale of the) most recently installed translator + * + * May return something different from the locale.name() of the + * QLocale passed in, because Calamares will munge some names and + * may remap translations. + */ DLLEXPORT QString translatorLocaleName(); +/** @brief Loads translations into the given @p translator + * + * This function is not intended for general use: it is for those special + * cases where modules need their own translator / translations for data + * that is locale to the module. Tries to load a .qm from "sensible" + * locations, which are the same ones that installTranslator() would use. + * Takes local-translations into account. + * + * Note that @p prefix should end with an underscore '_' -- this function + * does not introduce one by itself. + * + * @returns @c true on success + */ +DLLEXPORT bool loadTranslator( const QLocale& locale, const QString& prefix, QTranslator* translator ); + /** @brief Set @p allow to true to load translations from current dir. * * If false, (or never called) the translations are loaded only from diff --git a/src/libcalamares/utils/Yaml.cpp b/src/libcalamares/utils/Yaml.cpp index b787589c6..dd7523ae4 100644 --- a/src/libcalamares/utils/Yaml.cpp +++ b/src/libcalamares/utils/Yaml.cpp @@ -52,9 +52,7 @@ yamlToVariant( const YAML::Node& node ) case YAML::NodeType::Undefined: return QVariant(); } - - // NOTREACHED - return QVariant(); + __builtin_unreachable(); } diff --git a/src/libcalamaresui/utils/QtCompat.h b/src/libcalamaresui/utils/QtCompat.h new file mode 100644 index 000000000..d53c01e0b --- /dev/null +++ b/src/libcalamaresui/utils/QtCompat.h @@ -0,0 +1,42 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * Calamares is Free Software: see the License-Identifier above. + * + */ + +/**@file Handle compatibility and deprecations across Qt versions + * + * Since Calamares is supposed to work with Qt 5.9 or later, it covers a + * lot of changes in the Qt API. Especially the later Qt 5.15 (last LTS) + * versions deprecate a number of enum values and parts of the QWidgets + * API. This file adjusts for that by introducing suitable aliases + * and workaround-functions. + * + * For a similar approach for QtCore, see libcalamares/utils/String.h + */ + +#ifndef UTILS_QTCOMPAT_H +#define UTILS_QTCOMPAT_H + +#include + +/* Avoid warnings about QPalette changes */ +constexpr static const auto WindowBackground = +#if QT_VERSION < QT_VERSION_CHECK( 5, 15, 0 ) + QPalette::Background +#else + QPalette::Window +#endif + ; + +constexpr static const auto WindowText = +#if QT_VERSION < QT_VERSION_CHECK( 5, 15, 0 ) + QPalette::Foreground +#else + QPalette::WindowText +#endif + ; + +#endif diff --git a/src/libcalamaresui/viewpages/ExecutionViewStep.cpp b/src/libcalamaresui/viewpages/ExecutionViewStep.cpp index e3498c62d..bb629b217 100644 --- a/src/libcalamaresui/viewpages/ExecutionViewStep.cpp +++ b/src/libcalamaresui/viewpages/ExecutionViewStep.cpp @@ -42,7 +42,7 @@ makeSlideshow( QWidget* parent ) return new Calamares::SlideshowPictures( parent ); #ifdef WITH_QML case 1: - FALLTHRU; + [[fallthrough]]; case 2: return new Calamares::SlideshowQML( parent ); #endif diff --git a/src/modules/dummypythonqt/lang/dummypythonqt.pot b/src/modules/dummypythonqt/lang/dummypythonqt.pot index b1665e503..e3a5ff33d 100644 --- a/src/modules/dummypythonqt/lang/dummypythonqt.pot +++ b/src/modules/dummypythonqt/lang/dummypythonqt.pot @@ -2,41 +2,41 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. -# +# #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-10-15 12:53+0200\n" +"POT-Creation-Date: 2020-11-09 15:12+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: \n" #: src/modules/dummypythonqt/main.py:75 msgid "Click me!" -msgstr "Click me!" +msgstr "" #: src/modules/dummypythonqt/main.py:85 msgid "A new QLabel." -msgstr "A new QLabel." +msgstr "" #: src/modules/dummypythonqt/main.py:88 msgid "Dummy PythonQt ViewStep" -msgstr "Dummy PythonQt ViewStep" +msgstr "" #: src/modules/dummypythonqt/main.py:174 msgid "The Dummy PythonQt Job" -msgstr "The Dummy PythonQt Job" +msgstr "" #: src/modules/dummypythonqt/main.py:177 msgid "This is the Dummy PythonQt Job. The dummy job says: {}" -msgstr "This is the Dummy PythonQt Job. The dummy job says: {}" +msgstr "" #: src/modules/dummypythonqt/main.py:181 msgid "A status message for Dummy PythonQt Job." -msgstr "A status message for Dummy PythonQt Job." +msgstr "" diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index 7a94a8acc..c3bc0b95a 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -161,7 +161,10 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): hooks.append("usr") if encrypt_hook: - hooks.append("encrypt") + if detect_plymouth(): + hooks.append("plymouth-encrypt") + else: + hooks.append("encrypt") if not unencrypted_separate_boot and \ os.path.isfile( os.path.join(root_mount_point, "crypto_keyfile.bin") diff --git a/src/modules/keyboard/AdditionalLayoutInfo.h b/src/modules/keyboard/AdditionalLayoutInfo.h new file mode 100644 index 000000000..61e854d3b --- /dev/null +++ b/src/modules/keyboard/AdditionalLayoutInfo.h @@ -0,0 +1,25 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Artem Grinev + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#ifndef KEYBOARD_ADDITIONAL_LAYOUT_INFO_H +#define KEYBOARD_ADDITIONAL_LAYOUT_INFO_H + +#include + +struct AdditionalLayoutInfo +{ + QString additionalLayout; + QString additionalVariant; + + QString groupSwitcher; + + QString vconsoleKeymap; +}; + +#endif diff --git a/src/modules/keyboard/CMakeLists.txt b/src/modules/keyboard/CMakeLists.txt index e9037bc03..32e9a0592 100644 --- a/src/modules/keyboard/CMakeLists.txt +++ b/src/modules/keyboard/CMakeLists.txt @@ -7,6 +7,7 @@ calamares_add_plugin( keyboard TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES + Config.cpp KeyboardViewStep.cpp KeyboardPage.cpp KeyboardLayoutModel.cpp diff --git a/src/modules/keyboard/Config.cpp b/src/modules/keyboard/Config.cpp index 11a20bbb7..a2f200a52 100644 --- a/src/modules/keyboard/Config.cpp +++ b/src/modules/keyboard/Config.cpp @@ -18,170 +18,28 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" #include "utils/String.h" +#include "utils/Variant.h" #include #include #include -KeyboardModelsModel::KeyboardModelsModel( QObject* parent ) - : QAbstractListModel( parent ) +/* Returns stringlist with suitable setxkbmap command-line arguments + * to set the given @p model. + */ +static inline QStringList +xkbmap_model_args( const QString& model ) { - detectModels(); + QStringList r { "-model", model }; + return r; } -void -KeyboardModelsModel::detectModels() -{ - beginResetModel(); - const auto models = KeyboardGlobal::getKeyboardModels(); - auto index = -1; - for ( const auto& key : models.keys() ) - { - index++; - m_list << QMap< QString, QString > { { "label", key }, { "key", models[ key ] } }; - if ( models[ key ] == "pc105" ) - { - this->setCurrentIndex( index ); - } - } - endResetModel(); -} - -void -KeyboardModelsModel::refresh() -{ - m_list.clear(); - setCurrentIndex( -1 ); - detectModels(); -} - -QVariant -KeyboardModelsModel::data( const QModelIndex& index, int role ) const -{ - if ( !index.isValid() ) - { - return QVariant(); - } - const auto item = m_list.at( index.row() ); - return role == Qt::DisplayRole ? item[ "label" ] : item[ "key" ]; -} - -int -KeyboardModelsModel::rowCount( const QModelIndex& ) const -{ - return m_list.count(); -} - -QHash< int, QByteArray > -KeyboardModelsModel::roleNames() const -{ - return { { Qt::DisplayRole, "label" }, { Qt::UserRole, "key" } }; -} - -int -KeyboardModelsModel::currentIndex() const -{ - return m_currentIndex; -} - -const QMap< QString, QString > -KeyboardModelsModel::item( const int& index ) const -{ - if ( index >= m_list.count() || index < 0 ) - { - return QMap< QString, QString >(); - } - - return m_list.at( index ); -} - -const QMap< QString, QString > -KeyboardVariantsModel::item( const int& index ) const -{ - if ( index >= m_list.count() || index < 0 ) - { - return QMap< QString, QString >(); - } - - return m_list.at( index ); -} - -void -KeyboardModelsModel::setCurrentIndex( const int& index ) -{ - if ( index >= m_list.count() || index < 0 ) - { - return; - } - - m_currentIndex = index; - emit currentIndexChanged( m_currentIndex ); -} - -KeyboardVariantsModel::KeyboardVariantsModel( QObject* parent ) - : QAbstractListModel( parent ) -{ -} - -int -KeyboardVariantsModel::currentIndex() const -{ - return m_currentIndex; -} - -void -KeyboardVariantsModel::setCurrentIndex( const int& index ) -{ - if ( index >= m_list.count() || index < 0 ) - { - return; - } - - m_currentIndex = index; - emit currentIndexChanged( m_currentIndex ); -} - -QVariant -KeyboardVariantsModel::data( const QModelIndex& index, int role ) const -{ - if ( !index.isValid() ) - { - return QVariant(); - } - const auto item = m_list.at( index.row() ); - return role == Qt::DisplayRole ? item[ "label" ] : item[ "key" ]; -} - -int -KeyboardVariantsModel::rowCount( const QModelIndex& ) const -{ - return m_list.count(); -} - -QHash< int, QByteArray > -KeyboardVariantsModel::roleNames() const -{ - return { { Qt::DisplayRole, "label" }, { Qt::UserRole, "key" } }; -} - -void -KeyboardVariantsModel::setVariants( QMap< QString, QString > variants ) -{ - m_list.clear(); - beginResetModel(); - for ( const auto& key : variants.keys() ) - { - const auto item = QMap< QString, QString > { { "label", key }, { "key", variants[ key ] } }; - m_list << item; - } - endResetModel(); -} /* Returns stringlist with suitable setxkbmap command-line arguments * to set the given @p layout and @p variant. */ static inline QStringList -xkbmap_args( const QString& layout, const QString& variant ) +xkbmap_layout_args( const QString& layout, const QString& variant ) { QStringList r { "-layout", layout }; if ( !variant.isEmpty() ) @@ -191,6 +49,103 @@ xkbmap_args( const QString& layout, const QString& variant ) return r; } +static inline QStringList +xkbmap_layout_args( const QStringList& layouts, + const QStringList& variants, + const QString& switchOption = "grp:alt_shift_toggle" ) +{ + if ( layouts.size() != variants.size() ) + { + cError() << "Number of layouts and variants must be equal (empty string should be used if there is no " + "corresponding variant)"; + return QStringList(); + } + + QStringList r { "-layout", layouts.join( "," ) }; + + if ( !variants.isEmpty() ) + { + r << "-variant" << variants.join( "," ); + } + + if ( !switchOption.isEmpty() ) + { + r << "-option" << switchOption; + } + + return r; +} + +/* Returns group-switch setxkbd option if set + * or an empty string otherwise + */ +static inline QString +xkbmap_query_grp_option() +{ + QProcess setxkbmapQuery; + setxkbmapQuery.start( "setxkbmap", { "-query" } ); + setxkbmapQuery.waitForFinished(); + + QString outputLine; + + do + { + outputLine = setxkbmapQuery.readLine(); + } while ( setxkbmapQuery.canReadLine() && !outputLine.startsWith( "options:" ) ); + + if ( !outputLine.startsWith( "options:" ) ) + { + return QString(); + } + + int index = outputLine.indexOf( "grp:" ); + + if ( index == -1 ) + { + return QString(); + } + + //it's either in the end of line or before the other option so \s or , + int lastIndex = outputLine.indexOf( QRegExp( "[\\s,]" ), index ); + + return outputLine.mid( index, lastIndex - index ); +} + +AdditionalLayoutInfo +Config::getAdditionalLayoutInfo( const QString& layout ) +{ + QFile layoutTable( ":/non-ascii-layouts" ); + + if ( !layoutTable.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + cError() << "Non-ASCII layout table could not be opened"; + return AdditionalLayoutInfo(); + } + + QString tableLine; + + do + { + tableLine = layoutTable.readLine(); + } while ( layoutTable.canReadLine() && !tableLine.startsWith( layout ) ); + + if ( !tableLine.startsWith( layout ) ) + { + return AdditionalLayoutInfo(); + } + + QStringList tableEntries = tableLine.split( " ", SplitSkipEmptyParts ); + + AdditionalLayoutInfo r; + + r.additionalLayout = tableEntries[ 1 ]; + r.additionalVariant = tableEntries[ 2 ] == "-" ? "" : tableEntries[ 2 ]; + + r.vconsoleKeymap = tableEntries[ 3 ]; + + return r; +} + Config::Config( QObject* parent ) : QObject( parent ) , m_keyboardModelsModel( new KeyboardModelsModel( this ) ) @@ -201,9 +156,9 @@ Config::Config( QObject* parent ) // Connect signals and slots connect( m_keyboardModelsModel, &KeyboardModelsModel::currentIndexChanged, [&]( int index ) { - m_selectedModel = m_keyboardModelsModel->item( index ).value( "key", "pc105" ); - // Set Xorg keyboard model - QProcess::execute( "setxkbmap", QStringList { "-model", m_selectedModel } ); + // Set Xorg keyboard model + m_selectedModel = m_keyboardModelsModel->key( index ); + QProcess::execute( "setxkbmap", xkbmap_model_args( m_selectedModel ) ); emit prettyStatusChanged(); } ); @@ -214,9 +169,9 @@ Config::Config( QObject* parent ) } ); connect( m_keyboardVariantsModel, &KeyboardVariantsModel::currentIndexChanged, [&]( int index ) { - m_selectedVariant = m_keyboardVariantsModel->item( index )[ "key" ]; + // Set Xorg keyboard layout + variant + m_selectedVariant = m_keyboardVariantsModel->key( index ); - // Set Xorg keyboard layout if ( m_setxkbmapTimer.isActive() ) { m_setxkbmapTimer.stop(); @@ -224,8 +179,32 @@ Config::Config( QObject* parent ) } connect( &m_setxkbmapTimer, &QTimer::timeout, this, [=] { - QProcess::execute( "setxkbmap", xkbmap_args( m_selectedLayout, m_selectedVariant ) ); - cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant; + m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout ); + + if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() ) + { + m_additionalLayoutInfo.groupSwitcher = xkbmap_query_grp_option(); + + if ( m_additionalLayoutInfo.groupSwitcher.isEmpty() ) + { + m_additionalLayoutInfo.groupSwitcher = "grp:alt_shift_toggle"; + } + + QProcess::execute( "setxkbmap", + xkbmap_layout_args( { m_additionalLayoutInfo.additionalLayout, m_selectedLayout }, + { m_additionalLayoutInfo.additionalVariant, m_selectedVariant }, + m_additionalLayoutInfo.groupSwitcher ) ); + + + cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant << "(added " + << m_additionalLayoutInfo.additionalLayout << "-" << m_additionalLayoutInfo.additionalVariant + << " since current layout is not ASCII-capable)"; + } + else + { + QProcess::execute( "setxkbmap", xkbmap_layout_args( m_selectedLayout, m_selectedVariant ) ); + cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant; + } m_setxkbmapTimer.disconnect( this ); } ); m_setxkbmapTimer.start( QApplication::keyboardInputInterval() ); @@ -269,7 +248,7 @@ findLayout( const KeyboardLayoutModel* klm, const QString& currentLayout ) } void -Config::init() +Config::detectCurrentKeyboardLayout() { //### Detect current keyboard layout and variant QString currentLayout; @@ -281,18 +260,25 @@ Config::init() { const QStringList list = QString( process.readAll() ).split( "\n", SplitSkipEmptyParts ); - for ( QString line : list ) + // A typical line looks like + // xkb_symbols { include "pc+latin+ru:2+inet(evdev)+group(alt_shift_toggle)+ctrl(swapcaps)" }; + for ( const auto& line : list ) { - line = line.trimmed(); - if ( !line.startsWith( "xkb_symbols" ) ) + if ( !line.trimmed().startsWith( "xkb_symbols" ) ) { continue; } - line = line.remove( "}" ).remove( "{" ).remove( ";" ); - line = line.mid( line.indexOf( "\"" ) + 1 ); + int firstQuote = line.indexOf( '"' ); + int lastQuote = line.lastIndexOf( '"' ); - QStringList split = line.split( "+", SplitSkipEmptyParts ); + if ( firstQuote < 0 || lastQuote < 0 || lastQuote <= firstQuote ) + { + continue; + } + + QStringList split = line.mid( firstQuote + 1, lastQuote - firstQuote ).split( "+", SplitSkipEmptyParts ); + cDebug() << split; if ( split.size() >= 2 ) { currentLayout = split.at( 1 ); @@ -338,11 +324,11 @@ Config::prettyStatus() const { QString status; status += tr( "Set keyboard model to %1.
" ) - .arg( m_keyboardModelsModel->item( m_keyboardModelsModel->currentIndex() )[ "label" ] ); + .arg( m_keyboardModelsModel->label( m_keyboardModelsModel->currentIndex() ) ); QString layout = m_keyboardLayoutsModel->item( m_keyboardLayoutsModel->currentIndex() ).second.description; QString variant = m_keyboardVariantsModel->currentIndex() >= 0 - ? m_keyboardVariantsModel->item( m_keyboardVariantsModel->currentIndex() )[ "label" ] + ? m_keyboardVariantsModel->label( m_keyboardVariantsModel->currentIndex() ) : QString( "" ); status += tr( "Set keyboard layout to %1/%2." ).arg( layout, variant ); @@ -350,16 +336,17 @@ Config::prettyStatus() const } Calamares::JobList -Config::createJobs( const QString& xOrgConfFileName, const QString& convertedKeymapPath, bool writeEtcDefaultKeyboard ) +Config::createJobs() { QList< Calamares::job_ptr > list; Calamares::Job* j = new SetKeyboardLayoutJob( m_selectedModel, m_selectedLayout, m_selectedVariant, - xOrgConfFileName, - convertedKeymapPath, - writeEtcDefaultKeyboard ); + m_additionalLayoutInfo, + m_xOrgConfFileName, + m_convertedKeymapPath, + m_writeEtcDefaultKeyboard ); list.append( Calamares::job_ptr( j ) ); return list; @@ -393,13 +380,12 @@ Config::guessLayout( const QStringList& langParts ) cDebug() << "Next level:" << *countryPart; for ( int variantnumber = 0; variantnumber < m_keyboardVariantsModel->rowCount(); ++variantnumber ) { - if ( m_keyboardVariantsModel->item( variantnumber )[ "key" ].compare( *countryPart, - Qt::CaseInsensitive ) ) + if ( m_keyboardVariantsModel->key( variantnumber ).compare( *countryPart, Qt::CaseInsensitive ) + == 0 ) { m_keyboardVariantsModel->setCurrentIndex( variantnumber ); - cDebug() << Logger::SubEntry << "matched variant" - << m_keyboardVariantsModel->item( variantnumber )[ "key" ] << ' ' - << m_keyboardVariantsModel->item( variantnumber )[ "key" ]; + cDebug() << Logger::SubEntry << "matched variant" << *countryPart << ' ' + << m_keyboardVariantsModel->key( variantnumber ); } } } @@ -507,6 +493,13 @@ Config::finalize() { gs->insert( "keyboardLayout", m_selectedLayout ); gs->insert( "keyboardVariant", m_selectedVariant ); //empty means default variant + + if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() ) + { + gs->insert( "keyboardAdditionalLayout", m_additionalLayoutInfo.additionalLayout ); + gs->insert( "keyboardAdditionalLayout", m_additionalLayoutInfo.additionalVariant ); + gs->insert( "keyboardVConsoleKeymap", m_additionalLayoutInfo.vconsoleKeymap ); + } } //FIXME: also store keyboard model for something? @@ -529,3 +522,47 @@ Config::updateVariants( const QPersistentModelIndex& currentItem, QString curren } } } + +void +Config::setConfigurationMap( const QVariantMap& configurationMap ) +{ + using namespace CalamaresUtils; + + if ( configurationMap.contains( "xOrgConfFileName" ) + && configurationMap.value( "xOrgConfFileName" ).type() == QVariant::String + && !getString( configurationMap, "xOrgConfFileName" ).isEmpty() ) + { + m_xOrgConfFileName = getString( configurationMap, "xOrgConfFileName" ); + } + else + { + m_xOrgConfFileName = "00-keyboard.conf"; + } + + if ( configurationMap.contains( "convertedKeymapPath" ) + && configurationMap.value( "convertedKeymapPath" ).type() == QVariant::String + && !getString( configurationMap, "convertedKeymapPath" ).isEmpty() ) + { + m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" ); + } + else + { + m_convertedKeymapPath = QString(); + } + + if ( configurationMap.contains( "writeEtcDefaultKeyboard" ) + && configurationMap.value( "writeEtcDefaultKeyboard" ).type() == QVariant::Bool ) + { + m_writeEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true ); + } + else + { + m_writeEtcDefaultKeyboard = true; + } +} + +void +Config::retranslate() +{ + retranslateKeyboardModels(); +} diff --git a/src/modules/keyboard/Config.h b/src/modules/keyboard/Config.h index 44a893faa..90eeb0e7b 100644 --- a/src/modules/keyboard/Config.h +++ b/src/modules/keyboard/Config.h @@ -11,6 +11,7 @@ #ifndef KEYBOARD_CONFIG_H #define KEYBOARD_CONFIG_H +#include "AdditionalLayoutInfo.h" #include "Job.h" #include "KeyboardLayoutModel.h" @@ -20,63 +21,6 @@ #include #include -class KeyboardModelsModel : public QAbstractListModel -{ - Q_OBJECT - Q_PROPERTY( int currentIndex WRITE setCurrentIndex READ currentIndex NOTIFY currentIndexChanged ) - -public: - explicit KeyboardModelsModel( QObject* parent = nullptr ); - int rowCount( const QModelIndex& = QModelIndex() ) const override; - QVariant data( const QModelIndex& index, int role ) const override; - - void setCurrentIndex( const int& index ); - int currentIndex() const; - const QMap< QString, QString > item( const int& index ) const; - -public slots: - void refresh(); - -protected: - QHash< int, QByteArray > roleNames() const override; - -private: - int m_currentIndex = -1; - QVector< QMap< QString, QString > > m_list; - void detectModels(); - -signals: - void currentIndexChanged( int index ); -}; - -class KeyboardVariantsModel : public QAbstractListModel -{ - Q_OBJECT - Q_PROPERTY( int currentIndex WRITE setCurrentIndex READ currentIndex NOTIFY currentIndexChanged ) - -public: - explicit KeyboardVariantsModel( QObject* parent = nullptr ); - void setVariants( QMap< QString, QString > variants ); - - int rowCount( const QModelIndex& = QModelIndex() ) const override; - QVariant data( const QModelIndex& index, int role ) const override; - - void setCurrentIndex( const int& index ); - int currentIndex() const; - - const QMap< QString, QString > item( const int& index ) const; - -protected: - QHash< int, QByteArray > roleNames() const override; - -private: - int m_currentIndex = -1; - QVector< QMap< QString, QString > > m_list; - -signals: - void currentIndexChanged( int index ); -}; - class Config : public QObject { Q_OBJECT @@ -88,15 +32,46 @@ class Config : public QObject public: Config( QObject* parent = nullptr ); - void init(); + void detectCurrentKeyboardLayout(); - Calamares::JobList - createJobs( const QString& xOrgConfFileName, const QString& convertedKeymapPath, bool writeEtcDefaultKeyboard ); + Calamares::JobList createJobs(); QString prettyStatus() const; void onActivate(); void finalize(); + void setConfigurationMap( const QVariantMap& configurationMap ); + + static AdditionalLayoutInfo getAdditionalLayoutInfo( const QString& layout ); + + /* A model is a physical configuration of a keyboard, e.g. 105-key PC + * or TKL 88-key physical size. + */ + KeyboardModelsModel* keyboardModels() const; + /* A layout describes the basic keycaps / language assigned to the + * keys of the physical keyboard, e.g. English (US) or Russian. + */ + KeyboardLayoutModel* keyboardLayouts() const; + /* A variant describes a variant of the basic keycaps; this can + * concern options (dead keys), or different placements of the keycaps + * (dvorak). + */ + KeyboardVariantsModel* keyboardVariants() const; + + /** @brief Call this to change application language + * + * The models (for keyboard model, layouts and variants) provide + * translations of strings in the xkb table, so need to be + * notified of language changes as well. + * + * Only widgets get LanguageChange events, so one of them will + * need to call this. + */ + void retranslate(); + +signals: + void prettyStatusChanged(); + private: void guessLayout( const QStringList& langParts ); void updateVariants( const QPersistentModelIndex& currentItem, QString currentVariant = QString() ); @@ -108,16 +83,16 @@ private: QString m_selectedLayout; QString m_selectedModel; QString m_selectedVariant; + + // Layout (and corresponding info) added if current one doesn't support ASCII (e.g. Russian or Japanese) + AdditionalLayoutInfo m_additionalLayoutInfo; + QTimer m_setxkbmapTimer; -protected: - KeyboardModelsModel* keyboardModels() const; - KeyboardLayoutModel* keyboardLayouts() const; - KeyboardVariantsModel* keyboardVariants() const; - - -signals: - void prettyStatusChanged(); + // From configuration + QString m_xOrgConfFileName; + QString m_convertedKeymapPath; + bool m_writeEtcDefaultKeyboard = true; }; diff --git a/src/modules/keyboard/KeyboardData_p.cxxtr b/src/modules/keyboard/KeyboardData_p.cxxtr new file mode 100644 index 000000000..39783035a --- /dev/null +++ b/src/modules/keyboard/KeyboardData_p.cxxtr @@ -0,0 +1,825 @@ +/* GENERATED FILE DO NOT EDIT +* +* === This file is part of Calamares - === +* +* SPDX-FileCopyrightText: no +* SPDX-License-Identifier: CC0-1.0 +* +* This file is derived from base.lst in the Xorg distribution +* +*/ + +/** THIS FILE EXISTS ONLY FOR TRANSLATIONS PURPOSES **/ + +// *INDENT-OFF* +// clang-format off +/* This returns a reference to local, which is a terrible idea. + * Good thing it's not meant to be compiled. + */ +class kb_models : public QObject { +Q_OBJECT +public: + const QStringList& table() + { + return QStringList { + tr("A4Tech KB-21", "kb_models"), + tr("A4Tech KBS-8", "kb_models"), + tr("A4Tech Wireless Desktop RFKB-23", "kb_models"), + tr("Acer AirKey V", "kb_models"), + tr("Acer C300", "kb_models"), + tr("Acer Ferrari 4000", "kb_models"), + tr("Acer laptop", "kb_models"), + tr("Advance Scorpius KI", "kb_models"), + tr("Apple", "kb_models"), + tr("Apple Aluminium (ANSI)", "kb_models"), + tr("Apple Aluminium (ISO)", "kb_models"), + tr("Apple Aluminium (JIS)", "kb_models"), + tr("Apple laptop", "kb_models"), + tr("Asus laptop", "kb_models"), + tr("Azona RF2300 wireless Internet", "kb_models"), + tr("BTC 5090", "kb_models"), + tr("BTC 5113RF Multimedia", "kb_models"), + tr("BTC 5126T", "kb_models"), + tr("BTC 6301URF", "kb_models"), + tr("BTC 9000", "kb_models"), + tr("BTC 9000A", "kb_models"), + tr("BTC 9001AH", "kb_models"), + tr("BTC 9019U", "kb_models"), + tr("BTC 9116U Mini Wireless Internet and Gaming", "kb_models"), + tr("BenQ X-Touch", "kb_models"), + tr("BenQ X-Touch 730", "kb_models"), + tr("BenQ X-Touch 800", "kb_models"), + tr("Brother Internet", "kb_models"), + tr("Cherry B.UNLIMITED", "kb_models"), + tr("Cherry Blue Line CyBo@rd", "kb_models"), + tr("Cherry Blue Line CyBo@rd (alt.)", "kb_models"), + tr("Cherry CyBo@rd USB-Hub", "kb_models"), + tr("Cherry CyMotion Expert", "kb_models"), + tr("Cherry CyMotion Master Linux", "kb_models"), + tr("Cherry CyMotion Master XPress", "kb_models"), + tr("Chicony Internet", "kb_models"), + tr("Chicony KB-9885", "kb_models"), + tr("Chicony KU-0108", "kb_models"), + tr("Chicony KU-0420", "kb_models"), + tr("Chromebook", "kb_models"), + tr("Classmate PC", "kb_models"), + tr("Compaq Armada laptop", "kb_models"), + tr("Compaq Easy Access", "kb_models"), + tr("Compaq Internet (13 keys)", "kb_models"), + tr("Compaq Internet (18 keys)", "kb_models"), + tr("Compaq Internet (7 keys)", "kb_models"), + tr("Compaq Presario laptop", "kb_models"), + tr("Compaq iPaq", "kb_models"), + tr("Creative Desktop Wireless 7000", "kb_models"), + tr("DTK2000", "kb_models"), + tr("Dell", "kb_models"), + tr("Dell 101-key PC", "kb_models"), + tr("Dell Inspiron 6000/8000 laptop", "kb_models"), + tr("Dell Latitude laptop", "kb_models"), + tr("Dell Precision M laptop", "kb_models"), + tr("Dell Precision M65 laptop", "kb_models"), + tr("Dell SK-8125", "kb_models"), + tr("Dell SK-8135", "kb_models"), + tr("Dell USB Multimedia", "kb_models"), + tr("Dexxa Wireless Desktop", "kb_models"), + tr("Diamond 9801/9802", "kb_models"), + tr("Ennyah DKB-1008", "kb_models"), + tr("Everex STEPnote", "kb_models"), + tr("FL90", "kb_models"), + tr("Fujitsu-Siemens Amilo laptop", "kb_models"), + tr("Generic 101-key PC", "kb_models"), + tr("Generic 102-key PC", "kb_models"), + tr("Generic 104-key PC", "kb_models"), + tr("Generic 104-key PC with L-shaped Enter key", "kb_models"), + tr("Generic 105-key PC", "kb_models"), + tr("Generic 86-key PC", "kb_models"), + tr("Genius Comfy KB-12e", "kb_models"), + tr("Genius Comfy KB-16M/Multimedia KWD-910", "kb_models"), + tr("Genius Comfy KB-21e-Scroll", "kb_models"), + tr("Genius KB-19e NB", "kb_models"), + tr("Genius KKB-2050HS", "kb_models"), + tr("Gyration", "kb_models"), + tr("Happy Hacking", "kb_models"), + tr("Happy Hacking for Mac", "kb_models"), + tr("Hewlett-Packard Internet", "kb_models"), + tr("Hewlett-Packard Mini 110 laptop", "kb_models"), + tr("Hewlett-Packard NEC SK-2500 Multimedia", "kb_models"), + tr("Hewlett-Packard Omnibook 500", "kb_models"), + tr("Hewlett-Packard Omnibook 500 FA", "kb_models"), + tr("Hewlett-Packard Omnibook 6000/6100", "kb_models"), + tr("Hewlett-Packard Omnibook XE3 GC", "kb_models"), + tr("Hewlett-Packard Omnibook XE3 GF", "kb_models"), + tr("Hewlett-Packard Omnibook XT1000", "kb_models"), + tr("Hewlett-Packard Pavilion ZT1100", "kb_models"), + tr("Hewlett-Packard Pavilion dv5", "kb_models"), + tr("Hewlett-Packard nx9020", "kb_models"), + tr("Honeywell Euroboard", "kb_models"), + tr("IBM Rapid Access", "kb_models"), + tr("IBM Rapid Access II", "kb_models"), + tr("IBM Space Saver", "kb_models"), + tr("IBM ThinkPad 560Z/600/600E/A22E", "kb_models"), + tr("IBM ThinkPad R60/T60/R61/T61", "kb_models"), + tr("IBM ThinkPad Z60m/Z60t/Z61m/Z61t", "kb_models"), + tr("Keytronic FlexPro", "kb_models"), + tr("Kinesis", "kb_models"), + tr("Logitech", "kb_models"), + tr("Logitech Access", "kb_models"), + tr("Logitech Cordless Desktop", "kb_models"), + tr("Logitech Cordless Desktop (alt.)", "kb_models"), + tr("Logitech Cordless Desktop EX110", "kb_models"), + tr("Logitech Cordless Desktop LX-300", "kb_models"), + tr("Logitech Cordless Desktop Navigator", "kb_models"), + tr("Logitech Cordless Desktop Optical", "kb_models"), + tr("Logitech Cordless Desktop Pro (2nd alt.)", "kb_models"), + tr("Logitech Cordless Desktop iTouch", "kb_models"), + tr("Logitech Cordless Freedom/Desktop Navigator", "kb_models"), + tr("Logitech G15 extra keys via G15daemon", "kb_models"), + tr("Logitech Internet", "kb_models"), + tr("Logitech Internet 350", "kb_models"), + tr("Logitech Internet Navigator", "kb_models"), + tr("Logitech Ultra-X", "kb_models"), + tr("Logitech Ultra-X Cordless Media Desktop", "kb_models"), + tr("Logitech diNovo", "kb_models"), + tr("Logitech diNovo Edge", "kb_models"), + tr("Logitech iTouch", "kb_models"), + tr("Logitech iTouch Cordless Y-RB6", "kb_models"), + tr("Logitech iTouch Internet Navigator SE", "kb_models"), + tr("Logitech iTouch Internet Navigator SE USB", "kb_models"), + tr("MacBook/MacBook Pro", "kb_models"), + tr("MacBook/MacBook Pro (intl.)", "kb_models"), + tr("Macintosh", "kb_models"), + tr("Macintosh Old", "kb_models"), + tr("Memorex MX1998", "kb_models"), + tr("Memorex MX2500 EZ-Access", "kb_models"), + tr("Memorex MX2750", "kb_models"), + tr("Microsoft Comfort Curve 2000", "kb_models"), + tr("Microsoft Internet", "kb_models"), + tr("Microsoft Internet Pro (Swedish)", "kb_models"), + tr("Microsoft Natural", "kb_models"), + tr("Microsoft Natural Elite", "kb_models"), + tr("Microsoft Natural Ergonomic 4000", "kb_models"), + tr("Microsoft Natural Pro OEM", "kb_models"), + tr("Microsoft Natural Pro USB/Internet Pro", "kb_models"), + tr("Microsoft Natural Pro/Internet Pro", "kb_models"), + tr("Microsoft Natural Wireless Ergonomic 7000", "kb_models"), + tr("Microsoft Office Keyboard", "kb_models"), + tr("Microsoft Surface", "kb_models"), + tr("Microsoft Wireless Multimedia 1.0A", "kb_models"), + tr("NEC SK-1300", "kb_models"), + tr("NEC SK-2500", "kb_models"), + tr("NEC SK-6200", "kb_models"), + tr("NEC SK-7100", "kb_models"), + tr("Northgate OmniKey 101", "kb_models"), + tr("OLPC", "kb_models"), + tr("Ortek Multimedia/Internet MCK-800", "kb_models"), + tr("PC-98", "kb_models"), + tr("Propeller Voyager KTEZ-1000", "kb_models"), + tr("QTronix Scorpius 98N+", "kb_models"), + tr("SVEN Ergonomic 2500", "kb_models"), + tr("SVEN Slim 303", "kb_models"), + tr("Samsung SDM 4500P", "kb_models"), + tr("Samsung SDM 4510P", "kb_models"), + tr("Sanwa Supply SKB-KG3", "kb_models"), + tr("Silvercrest Multimedia Wireless", "kb_models"), + tr("SteelSeries Apex 300 (Apex RAW)", "kb_models"), + tr("Sun Type 6 (Japanese)", "kb_models"), + tr("Sun Type 6 USB (Japanese)", "kb_models"), + tr("Sun Type 6 USB (Unix)", "kb_models"), + tr("Sun Type 6/7 USB", "kb_models"), + tr("Sun Type 6/7 USB (European)", "kb_models"), + tr("Sun Type 7 USB", "kb_models"), + tr("Sun Type 7 USB (European)", "kb_models"), + tr("Sun Type 7 USB (Japanese)/Japanese 106-key", "kb_models"), + tr("Sun Type 7 USB (Unix)", "kb_models"), + tr("Super Power Multimedia", "kb_models"), + tr("Symplon PaceBook tablet", "kb_models"), + tr("Targa Visionary 811", "kb_models"), + tr("Toshiba Satellite S3000", "kb_models"), + tr("Truly Ergonomic 227", "kb_models"), + tr("Truly Ergonomic 229", "kb_models"), + tr("Truly Ergonomic Computer Keyboard Model 227 (Wide Alt keys)", "kb_models"), + tr("Truly Ergonomic Computer Keyboard Model 229 (Standard sized Alt keys, additional Super and Menu key)", "kb_models"), + tr("Trust Direct Access", "kb_models"), + tr("Trust Slimline", "kb_models"), + tr("Trust Wireless Classic", "kb_models"), + tr("TypeMatrix EZ-Reach 2020", "kb_models"), + tr("TypeMatrix EZ-Reach 2030 PS2", "kb_models"), + tr("TypeMatrix EZ-Reach 2030 USB", "kb_models"), + tr("TypeMatrix EZ-Reach 2030 USB (102/105:EU mode)", "kb_models"), + tr("TypeMatrix EZ-Reach 2030 USB (106:JP mode)", "kb_models"), + tr("Unitek KB-1925", "kb_models"), + tr("ViewSonic KU-306 Internet", "kb_models"), + tr("Winbook Model XP5", "kb_models"), + tr("Yahoo! Internet", "kb_models"), + tr("eMachines m6800 laptop", "kb_models"), + QString() + }; +} +} + +/* This returns a reference to local, which is a terrible idea. + * Good thing it's not meant to be compiled. + */ +class kb_layouts : public QObject { +Q_OBJECT +public: + const QStringList& table() + { + return QStringList { + tr("Afghani", "kb_layouts"), + tr("Albanian", "kb_layouts"), + tr("Amharic", "kb_layouts"), + tr("Arabic", "kb_layouts"), + tr("Arabic (Morocco)", "kb_layouts"), + tr("Arabic (Syria)", "kb_layouts"), + tr("Armenian", "kb_layouts"), + tr("Azerbaijani", "kb_layouts"), + tr("Bambara", "kb_layouts"), + tr("Bangla", "kb_layouts"), + tr("Belarusian", "kb_layouts"), + tr("Belgian", "kb_layouts"), + tr("Bosnian", "kb_layouts"), + tr("Braille", "kb_layouts"), + tr("Bulgarian", "kb_layouts"), + tr("Burmese", "kb_layouts"), + tr("Chinese", "kb_layouts"), + tr("Croatian", "kb_layouts"), + tr("Czech", "kb_layouts"), + tr("Danish", "kb_layouts"), + tr("Dhivehi", "kb_layouts"), + tr("Dutch", "kb_layouts"), + tr("Dzongkha", "kb_layouts"), + tr("English (Australian)", "kb_layouts"), + tr("English (Cameroon)", "kb_layouts"), + tr("English (Ghana)", "kb_layouts"), + tr("English (Nigeria)", "kb_layouts"), + tr("English (South Africa)", "kb_layouts"), + tr("English (UK)", "kb_layouts"), + tr("English (US)", "kb_layouts"), + tr("Esperanto", "kb_layouts"), + tr("Estonian", "kb_layouts"), + tr("Faroese", "kb_layouts"), + tr("Filipino", "kb_layouts"), + tr("Finnish", "kb_layouts"), + tr("French", "kb_layouts"), + tr("French (Canada)", "kb_layouts"), + tr("French (Democratic Republic of the Congo)", "kb_layouts"), + tr("French (Guinea)", "kb_layouts"), + tr("French (Togo)", "kb_layouts"), + tr("Georgian", "kb_layouts"), + tr("German", "kb_layouts"), + tr("German (Austria)", "kb_layouts"), + tr("German (Switzerland)", "kb_layouts"), + tr("Greek", "kb_layouts"), + tr("Hebrew", "kb_layouts"), + tr("Hungarian", "kb_layouts"), + tr("Icelandic", "kb_layouts"), + tr("Indian", "kb_layouts"), + tr("Indonesian (Arab Melayu, phonetic)", "kb_layouts"), + tr("Indonesian (Javanese)", "kb_layouts"), + tr("Iraqi", "kb_layouts"), + tr("Irish", "kb_layouts"), + tr("Italian", "kb_layouts"), + tr("Japanese", "kb_layouts"), + tr("Japanese (PC-98)", "kb_layouts"), + tr("Kabylian (azerty layout, no dead keys)", "kb_layouts"), + tr("Kazakh", "kb_layouts"), + tr("Khmer (Cambodia)", "kb_layouts"), + tr("Korean", "kb_layouts"), + tr("Kyrgyz", "kb_layouts"), + tr("Lao", "kb_layouts"), + tr("Latvian", "kb_layouts"), + tr("Lithuanian", "kb_layouts"), + tr("Macedonian", "kb_layouts"), + tr("Malay (Jawi, Arabic Keyboard)", "kb_layouts"), + tr("Maltese", "kb_layouts"), + tr("Maori", "kb_layouts"), + tr("Moldavian", "kb_layouts"), + tr("Mongolian", "kb_layouts"), + tr("Montenegrin", "kb_layouts"), + tr("Nepali", "kb_layouts"), + tr("Norwegian", "kb_layouts"), + tr("Persian", "kb_layouts"), + tr("Polish", "kb_layouts"), + tr("Portuguese", "kb_layouts"), + tr("Portuguese (Brazil)", "kb_layouts"), + tr("Romanian", "kb_layouts"), + tr("Russian", "kb_layouts"), + tr("Serbian", "kb_layouts"), + tr("Sinhala (phonetic)", "kb_layouts"), + tr("Slovak", "kb_layouts"), + tr("Slovenian", "kb_layouts"), + tr("Spanish", "kb_layouts"), + tr("Spanish (Latin American)", "kb_layouts"), + tr("Swahili (Kenya)", "kb_layouts"), + tr("Swahili (Tanzania)", "kb_layouts"), + tr("Swedish", "kb_layouts"), + tr("Taiwanese", "kb_layouts"), + tr("Tajik", "kb_layouts"), + tr("Thai", "kb_layouts"), + tr("Tswana", "kb_layouts"), + tr("Turkish", "kb_layouts"), + tr("Turkmen", "kb_layouts"), + tr("Ukrainian", "kb_layouts"), + tr("Urdu (Pakistan)", "kb_layouts"), + tr("Uzbek", "kb_layouts"), + tr("Vietnamese", "kb_layouts"), + tr("Wolof", "kb_layouts"), + QString() + }; +} +} + +/* This returns a reference to local, which is a terrible idea. + * Good thing it's not meant to be compiled. + */ +class kb_variants : public QObject { +Q_OBJECT +public: + const QStringList& table() + { + return QStringList { + tr("Akan", "kb_variants"), + tr("Albanian (Plisi)", "kb_variants"), + tr("Albanian (Veqilharxhi)", "kb_variants"), + tr("Arabic (AZERTY)", "kb_variants"), + tr("Arabic (AZERTY, Eastern Arabic numerals)", "kb_variants"), + tr("Arabic (Algeria)", "kb_variants"), + tr("Arabic (Buckwalter)", "kb_variants"), + tr("Arabic (Eastern Arabic numerals)", "kb_variants"), + tr("Arabic (Macintosh)", "kb_variants"), + tr("Arabic (OLPC)", "kb_variants"), + tr("Arabic (Pakistan)", "kb_variants"), + tr("Arabic (QWERTY)", "kb_variants"), + tr("Arabic (QWERTY, Eastern Arabic numerals)", "kb_variants"), + tr("Armenian (alt. eastern)", "kb_variants"), + tr("Armenian (alt. phonetic)", "kb_variants"), + tr("Armenian (eastern)", "kb_variants"), + tr("Armenian (phonetic)", "kb_variants"), + tr("Armenian (western)", "kb_variants"), + tr("Asturian (Spain, with bottom-dot H and L)", "kb_variants"), + tr("Avatime", "kb_variants"), + tr("Azerbaijani (Cyrillic)", "kb_variants"), + tr("Bangla (India)", "kb_variants"), + tr("Bangla (India, Baishakhi Inscript)", "kb_variants"), + tr("Bangla (India, Baishakhi)", "kb_variants"), + tr("Bangla (India, Bornona)", "kb_variants"), + tr("Bangla (India, Gitanjali)", "kb_variants"), + tr("Bangla (India, Probhat)", "kb_variants"), + tr("Bangla (Probhat)", "kb_variants"), + tr("Bashkirian", "kb_variants"), + tr("Belarusian (Latin)", "kb_variants"), + tr("Belarusian (intl.)", "kb_variants"), + tr("Belarusian (legacy)", "kb_variants"), + tr("Belgian (ISO, alt.)", "kb_variants"), + tr("Belgian (Latin-9 only, alt.)", "kb_variants"), + tr("Belgian (Sun dead keys)", "kb_variants"), + tr("Belgian (Sun dead keys, alt.)", "kb_variants"), + tr("Belgian (Wang 724 AZERTY)", "kb_variants"), + tr("Belgian (alt.)", "kb_variants"), + tr("Belgian (no dead keys)", "kb_variants"), + tr("Berber (Morocco, Tifinagh alt.)", "kb_variants"), + tr("Berber (Morocco, Tifinagh extended phonetic)", "kb_variants"), + tr("Berber (Morocco, Tifinagh extended)", "kb_variants"), + tr("Berber (Morocco, Tifinagh phonetic)", "kb_variants"), + tr("Berber (Morocco, Tifinagh phonetic, alt.)", "kb_variants"), + tr("Berber (Morocco, Tifinagh)", "kb_variants"), + tr("Bosnian (US)", "kb_variants"), + tr("Bosnian (US, with Bosnian digraphs)", "kb_variants"), + tr("Bosnian (with Bosnian digraphs)", "kb_variants"), + tr("Bosnian (with guillemets)", "kb_variants"), + tr("Braille (left-handed inverted thumb)", "kb_variants"), + tr("Braille (left-handed)", "kb_variants"), + tr("Braille (right-handed inverted thumb)", "kb_variants"), + tr("Braille (right-handed)", "kb_variants"), + tr("Bulgarian (enhanced)", "kb_variants"), + tr("Bulgarian (new phonetic)", "kb_variants"), + tr("Bulgarian (traditional phonetic)", "kb_variants"), + tr("Burmese Zawgyi", "kb_variants"), + tr("Cameroon (AZERTY, intl.)", "kb_variants"), + tr("Cameroon (Dvorak, intl.)", "kb_variants"), + tr("Cameroon Multilingual (QWERTY, intl.)", "kb_variants"), + tr("Canadian (intl.)", "kb_variants"), + tr("Canadian (intl., 1st part)", "kb_variants"), + tr("Canadian (intl., 2nd part)", "kb_variants"), + tr("Catalan (Spain, with middle-dot L)", "kb_variants"), + tr("Cherokee", "kb_variants"), + tr("Chuvash", "kb_variants"), + tr("Chuvash (Latin)", "kb_variants"), + tr("CloGaelach", "kb_variants"), + tr("Crimean Tatar (Turkish Alt-Q)", "kb_variants"), + tr("Crimean Tatar (Turkish F)", "kb_variants"), + tr("Crimean Tatar (Turkish Q)", "kb_variants"), + tr("Croatian (US)", "kb_variants"), + tr("Croatian (US, with Croatian digraphs)", "kb_variants"), + tr("Croatian (with Croatian digraphs)", "kb_variants"), + tr("Croatian (with guillemets)", "kb_variants"), + tr("Czech (QWERTY)", "kb_variants"), + tr("Czech (QWERTY, Macintosh)", "kb_variants"), + tr("Czech (QWERTY, extended backslash)", "kb_variants"), + tr("Czech (UCW, only accented letters)", "kb_variants"), + tr("Czech (US, Dvorak, UCW support)", "kb_variants"), + tr("Czech (with <\|> key)", "kb_variants"), + tr("Danish (Dvorak)", "kb_variants"), + tr("Danish (Macintosh)", "kb_variants"), + tr("Danish (Macintosh, no dead keys)", "kb_variants"), + tr("Danish (Windows)", "kb_variants"), + tr("Danish (no dead keys)", "kb_variants"), + tr("Default", "kb_variants"), + tr("Dutch (Macintosh)", "kb_variants"), + tr("Dutch (Sun dead keys)", "kb_variants"), + tr("Dutch (standard)", "kb_variants"), + tr("English (Canada)", "kb_variants"), + tr("English (Colemak)", "kb_variants"), + tr("English (Dvorak)", "kb_variants"), + tr("English (Dvorak, alt. intl.)", "kb_variants"), + tr("English (Dvorak, intl., with dead keys)", "kb_variants"), + tr("English (Dvorak, left-handed)", "kb_variants"), + tr("English (Dvorak, right-handed)", "kb_variants"), + tr("English (Ghana, GILLBT)", "kb_variants"), + tr("English (Ghana, multilingual)", "kb_variants"), + tr("English (India, with rupee)", "kb_variants"), + tr("English (Macintosh)", "kb_variants"), + tr("English (Mali, US, Macintosh)", "kb_variants"), + tr("English (Mali, US, intl.)", "kb_variants"), + tr("English (Norman)", "kb_variants"), + tr("English (UK, Colemak)", "kb_variants"), + tr("English (UK, Dvorak)", "kb_variants"), + tr("English (UK, Dvorak, with UK punctuation)", "kb_variants"), + tr("English (UK, Macintosh)", "kb_variants"), + tr("English (UK, Macintosh, intl.)", "kb_variants"), + tr("English (UK, extended, Windows)", "kb_variants"), + tr("English (UK, intl., with dead keys)", "kb_variants"), + tr("English (US, Symbolic)", "kb_variants"), + tr("English (US, alt. intl.)", "kb_variants"), + tr("English (US, euro on 5)", "kb_variants"), + tr("English (US, intl., with dead keys)", "kb_variants"), + tr("English (Workman)", "kb_variants"), + tr("English (Workman, intl., with dead keys)", "kb_variants"), + tr("English (classic Dvorak)", "kb_variants"), + tr("English (intl., with AltGr dead keys)", "kb_variants"), + tr("English (programmer Dvorak)", "kb_variants"), + tr("English (the divide/multiply toggle the layout)", "kb_variants"), + tr("Esperanto (Brazil, Nativo)", "kb_variants"), + tr("Esperanto (Portugal, Nativo)", "kb_variants"), + tr("Esperanto (legacy)", "kb_variants"), + tr("Estonian (Dvorak)", "kb_variants"), + tr("Estonian (US)", "kb_variants"), + tr("Estonian (no dead keys)", "kb_variants"), + tr("Ewe", "kb_variants"), + tr("Faroese (no dead keys)", "kb_variants"), + tr("Filipino (Capewell-Dvorak, Baybayin)", "kb_variants"), + tr("Filipino (Capewell-Dvorak, Latin)", "kb_variants"), + tr("Filipino (Capewell-QWERF 2006, Baybayin)", "kb_variants"), + tr("Filipino (Capewell-QWERF 2006, Latin)", "kb_variants"), + tr("Filipino (Colemak, Baybayin)", "kb_variants"), + tr("Filipino (Colemak, Latin)", "kb_variants"), + tr("Filipino (Dvorak, Baybayin)", "kb_variants"), + tr("Filipino (Dvorak, Latin)", "kb_variants"), + tr("Filipino (QWERTY, Baybayin)", "kb_variants"), + tr("Finnish (Macintosh)", "kb_variants"), + tr("Finnish (Windows)", "kb_variants"), + tr("Finnish (classic)", "kb_variants"), + tr("Finnish (classic, no dead keys)", "kb_variants"), + tr("French (AZERTY)", "kb_variants"), + tr("French (AZERTY, AFNOR)", "kb_variants"), + tr("French (BEPO)", "kb_variants"), + tr("French (BEPO, AFNOR)", "kb_variants"), + tr("French (BEPO, Latin-9 only)", "kb_variants"), + tr("French (Breton)", "kb_variants"), + tr("French (Cameroon)", "kb_variants"), + tr("French (Canada, Dvorak)", "kb_variants"), + tr("French (Canada, legacy)", "kb_variants"), + tr("French (Dvorak)", "kb_variants"), + tr("French (Macintosh)", "kb_variants"), + tr("French (Mali, alt.)", "kb_variants"), + tr("French (Morocco)", "kb_variants"), + tr("French (Sun dead keys)", "kb_variants"), + tr("French (Switzerland)", "kb_variants"), + tr("French (Switzerland, Macintosh)", "kb_variants"), + tr("French (Switzerland, Sun dead keys)", "kb_variants"), + tr("French (Switzerland, no dead keys)", "kb_variants"), + tr("French (US)", "kb_variants"), + tr("French (alt.)", "kb_variants"), + tr("French (alt., Latin-9 only)", "kb_variants"), + tr("French (alt., Sun dead keys)", "kb_variants"), + tr("French (alt., no dead keys)", "kb_variants"), + tr("French (legacy, alt.)", "kb_variants"), + tr("French (legacy, alt., Sun dead keys)", "kb_variants"), + tr("French (legacy, alt., no dead keys)", "kb_variants"), + tr("French (no dead keys)", "kb_variants"), + tr("Friulian (Italy)", "kb_variants"), + tr("Fula", "kb_variants"), + tr("Ga", "kb_variants"), + tr("Georgian (France, AZERTY Tskapo)", "kb_variants"), + tr("Georgian (Italy)", "kb_variants"), + tr("Georgian (MESS)", "kb_variants"), + tr("Georgian (ergonomic)", "kb_variants"), + tr("German (Austria, Macintosh)", "kb_variants"), + tr("German (Austria, Sun dead keys)", "kb_variants"), + tr("German (Austria, no dead keys)", "kb_variants"), + tr("German (Dvorak)", "kb_variants"), + tr("German (E1)", "kb_variants"), + tr("German (E2)", "kb_variants"), + tr("German (Macintosh)", "kb_variants"), + tr("German (Macintosh, no dead keys)", "kb_variants"), + tr("German (Neo 2)", "kb_variants"), + tr("German (QWERTY)", "kb_variants"), + tr("German (Sun dead keys)", "kb_variants"), + tr("German (Switzerland, Macintosh)", "kb_variants"), + tr("German (Switzerland, Sun dead keys)", "kb_variants"), + tr("German (Switzerland, legacy)", "kb_variants"), + tr("German (Switzerland, no dead keys)", "kb_variants"), + tr("German (T3)", "kb_variants"), + tr("German (US)", "kb_variants"), + tr("German (dead acute)", "kb_variants"), + tr("German (dead grave acute)", "kb_variants"), + tr("German (dead tilde)", "kb_variants"), + tr("German (no dead keys)", "kb_variants"), + tr("Greek (extended)", "kb_variants"), + tr("Greek (no dead keys)", "kb_variants"), + tr("Greek (polytonic)", "kb_variants"), + tr("Greek (simple)", "kb_variants"), + tr("Gujarati", "kb_variants"), + tr("Hanyu Pinyin (with AltGr dead keys)", "kb_variants"), + tr("Hausa (Ghana)", "kb_variants"), + tr("Hausa (Nigeria)", "kb_variants"), + tr("Hawaiian", "kb_variants"), + tr("Hebrew (Biblical, Tiro)", "kb_variants"), + tr("Hebrew (lyx)", "kb_variants"), + tr("Hebrew (phonetic)", "kb_variants"), + tr("Hindi (Bolnagri)", "kb_variants"), + tr("Hindi (KaGaPa, phonetic)", "kb_variants"), + tr("Hindi (Wx)", "kb_variants"), + tr("Hungarian (QWERTY)", "kb_variants"), + tr("Hungarian (QWERTY, 101-key, comma, dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 101-key, comma, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 101-key, dot, dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 101-key, dot, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 102-key, comma, dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 102-key, comma, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 102-key, dot, dead keys)", "kb_variants"), + tr("Hungarian (QWERTY, 102-key, dot, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 101-key, comma, dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 101-key, comma, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 101-key, dot, dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 101-key, dot, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 102-key, comma, dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 102-key, comma, no dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 102-key, dot, dead keys)", "kb_variants"), + tr("Hungarian (QWERTZ, 102-key, dot, no dead keys)", "kb_variants"), + tr("Hungarian (no dead keys)", "kb_variants"), + tr("Hungarian (standard)", "kb_variants"), + tr("Icelandic (Dvorak)", "kb_variants"), + tr("Icelandic (Macintosh)", "kb_variants"), + tr("Icelandic (Macintosh, legacy)", "kb_variants"), + tr("Icelandic (Sun dead keys)", "kb_variants"), + tr("Icelandic (no dead keys)", "kb_variants"), + tr("Igbo", "kb_variants"), + tr("Indic (phonetic, IPA)", "kb_variants"), + tr("Indonesian (Arab Melayu, extended phonetic)", "kb_variants"), + tr("Inuktitut", "kb_variants"), + tr("Irish (UnicodeExpert)", "kb_variants"), + tr("Italian (IBM 142)", "kb_variants"), + tr("Italian (Macintosh)", "kb_variants"), + tr("Italian (US)", "kb_variants"), + tr("Italian (Windows)", "kb_variants"), + tr("Italian (intl., with dead keys)", "kb_variants"), + tr("Italian (no dead keys)", "kb_variants"), + tr("Japanese (Dvorak)", "kb_variants"), + tr("Japanese (Kana 86)", "kb_variants"), + tr("Japanese (Kana)", "kb_variants"), + tr("Japanese (Macintosh)", "kb_variants"), + tr("Japanese (OADG 109A)", "kb_variants"), + tr("Kabylian (Algeria, Tifinagh)", "kb_variants"), + tr("Kabylian (azerty layout, with dead keys)", "kb_variants"), + tr("Kabylian (qwerty-gb layout, with dead keys)", "kb_variants"), + tr("Kabylian (qwerty-us layout, with dead keys)", "kb_variants"), + tr("Kalmyk", "kb_variants"), + tr("Kannada", "kb_variants"), + tr("Kannada (KaGaPa, phonetic)", "kb_variants"), + tr("Kashubian", "kb_variants"), + tr("Kazakh (Latin)", "kb_variants"), + tr("Kazakh (extended)", "kb_variants"), + tr("Kazakh (with Russian)", "kb_variants"), + tr("Kikuyu", "kb_variants"), + tr("Komi", "kb_variants"), + tr("Korean (101/104-key compatible)", "kb_variants"), + tr("Kurdish (Iran, Arabic-Latin)", "kb_variants"), + tr("Kurdish (Iran, F)", "kb_variants"), + tr("Kurdish (Iran, Latin Alt-Q)", "kb_variants"), + tr("Kurdish (Iran, Latin Q)", "kb_variants"), + tr("Kurdish (Iraq, Arabic-Latin)", "kb_variants"), + tr("Kurdish (Iraq, F)", "kb_variants"), + tr("Kurdish (Iraq, Latin Alt-Q)", "kb_variants"), + tr("Kurdish (Iraq, Latin Q)", "kb_variants"), + tr("Kurdish (Syria, F)", "kb_variants"), + tr("Kurdish (Syria, Latin Alt-Q)", "kb_variants"), + tr("Kurdish (Syria, Latin Q)", "kb_variants"), + tr("Kurdish (Turkey, F)", "kb_variants"), + tr("Kurdish (Turkey, Latin Alt-Q)", "kb_variants"), + tr("Kurdish (Turkey, Latin Q)", "kb_variants"), + tr("Kyrgyz (phonetic)", "kb_variants"), + tr("Lao (STEA)", "kb_variants"), + tr("Latvian (F)", "kb_variants"), + tr("Latvian (adapted)", "kb_variants"), + tr("Latvian (apostrophe)", "kb_variants"), + tr("Latvian (ergonomic, ŪGJRMV)", "kb_variants"), + tr("Latvian (modern)", "kb_variants"), + tr("Latvian (tilde)", "kb_variants"), + tr("Lithuanian (IBM LST 1205-92)", "kb_variants"), + tr("Lithuanian (LEKP)", "kb_variants"), + tr("Lithuanian (LEKPa)", "kb_variants"), + tr("Lithuanian (US)", "kb_variants"), + tr("Lithuanian (standard)", "kb_variants"), + tr("Lower Sorbian", "kb_variants"), + tr("Lower Sorbian (QWERTZ)", "kb_variants"), + tr("Macedonian (no dead keys)", "kb_variants"), + tr("Malay (Jawi, phonetic)", "kb_variants"), + tr("Malayalam", "kb_variants"), + tr("Malayalam (Lalitha)", "kb_variants"), + tr("Malayalam (enhanced Inscript, with rupee)", "kb_variants"), + tr("Maltese (UK, with AltGr overrides)", "kb_variants"), + tr("Maltese (US layout with AltGr overrides)", "kb_variants"), + tr("Maltese (US)", "kb_variants"), + tr("Manipuri (Eeyek)", "kb_variants"), + tr("Marathi (KaGaPa, phonetic)", "kb_variants"), + tr("Marathi (enhanced Inscript)", "kb_variants"), + tr("Mari", "kb_variants"), + tr("Mmuock", "kb_variants"), + tr("Moldavian (Gagauz)", "kb_variants"), + tr("Mongolian (Bichig)", "kb_variants"), + tr("Mongolian (Galik)", "kb_variants"), + tr("Mongolian (Manchu Galik)", "kb_variants"), + tr("Mongolian (Manchu)", "kb_variants"), + tr("Mongolian (Todo Galik)", "kb_variants"), + tr("Mongolian (Todo)", "kb_variants"), + tr("Mongolian (Xibe)", "kb_variants"), + tr("Montenegrin (Cyrillic)", "kb_variants"), + tr("Montenegrin (Cyrillic, ZE and ZHE swapped)", "kb_variants"), + tr("Montenegrin (Cyrillic, with guillemets)", "kb_variants"), + tr("Montenegrin (Latin, QWERTY)", "kb_variants"), + tr("Montenegrin (Latin, Unicode)", "kb_variants"), + tr("Montenegrin (Latin, Unicode, QWERTY)", "kb_variants"), + tr("Montenegrin (Latin, with guillemets)", "kb_variants"), + tr("Northern Saami (Finland)", "kb_variants"), + tr("Northern Saami (Norway)", "kb_variants"), + tr("Northern Saami (Norway, no dead keys)", "kb_variants"), + tr("Northern Saami (Sweden)", "kb_variants"), + tr("Norwegian (Colemak)", "kb_variants"), + tr("Norwegian (Dvorak)", "kb_variants"), + tr("Norwegian (Macintosh)", "kb_variants"), + tr("Norwegian (Macintosh, no dead keys)", "kb_variants"), + tr("Norwegian (Windows)", "kb_variants"), + tr("Norwegian (no dead keys)", "kb_variants"), + tr("Occitan", "kb_variants"), + tr("Ogham", "kb_variants"), + tr("Ogham (IS434)", "kb_variants"), + tr("Ol Chiki", "kb_variants"), + tr("Oriya", "kb_variants"), + tr("Ossetian (Georgia)", "kb_variants"), + tr("Ossetian (Windows)", "kb_variants"), + tr("Ossetian (legacy)", "kb_variants"), + tr("Pannonian Rusyn", "kb_variants"), + tr("Pashto", "kb_variants"), + tr("Pashto (Afghanistan, OLPC)", "kb_variants"), + tr("Persian (Afghanistan, Dari OLPC)", "kb_variants"), + tr("Persian (with Persian keypad)", "kb_variants"), + tr("Polish (British keyboard)", "kb_variants"), + tr("Polish (Dvorak)", "kb_variants"), + tr("Polish (Dvorak, with Polish quotes on key 1)", "kb_variants"), + tr("Polish (Dvorak, with Polish quotes on quotemark key)", "kb_variants"), + tr("Polish (QWERTZ)", "kb_variants"), + tr("Polish (legacy)", "kb_variants"), + tr("Polish (programmer Dvorak)", "kb_variants"), + tr("Portuguese (Brazil, Dvorak)", "kb_variants"), + tr("Portuguese (Brazil, IBM/Lenovo ThinkPad)", "kb_variants"), + tr("Portuguese (Brazil, Nativo for US keyboards)", "kb_variants"), + tr("Portuguese (Brazil, Nativo)", "kb_variants"), + tr("Portuguese (Brazil, no dead keys)", "kb_variants"), + tr("Portuguese (Macintosh)", "kb_variants"), + tr("Portuguese (Macintosh, Sun dead keys)", "kb_variants"), + tr("Portuguese (Macintosh, no dead keys)", "kb_variants"), + tr("Portuguese (Nativo for US keyboards)", "kb_variants"), + tr("Portuguese (Nativo)", "kb_variants"), + tr("Portuguese (Sun dead keys)", "kb_variants"), + tr("Portuguese (no dead keys)", "kb_variants"), + tr("Punjabi (Gurmukhi Jhelum)", "kb_variants"), + tr("Punjabi (Gurmukhi)", "kb_variants"), + tr("Romanian (Germany)", "kb_variants"), + tr("Romanian (Germany, no dead keys)", "kb_variants"), + tr("Romanian (Windows)", "kb_variants"), + tr("Romanian (cedilla)", "kb_variants"), + tr("Romanian (standard cedilla)", "kb_variants"), + tr("Romanian (standard)", "kb_variants"), + tr("Russian (Belarus)", "kb_variants"), + tr("Russian (Czech, phonetic)", "kb_variants"), + tr("Russian (DOS)", "kb_variants"), + tr("Russian (Georgia)", "kb_variants"), + tr("Russian (Germany, phonetic)", "kb_variants"), + tr("Russian (Kazakhstan, with Kazakh)", "kb_variants"), + tr("Russian (Macintosh)", "kb_variants"), + tr("Russian (Poland, phonetic Dvorak)", "kb_variants"), + tr("Russian (Sweden, phonetic)", "kb_variants"), + tr("Russian (Sweden, phonetic, no dead keys)", "kb_variants"), + tr("Russian (US, phonetic)", "kb_variants"), + tr("Russian (Ukraine, standard RSTU)", "kb_variants"), + tr("Russian (legacy)", "kb_variants"), + tr("Russian (phonetic)", "kb_variants"), + tr("Russian (phonetic, AZERTY)", "kb_variants"), + tr("Russian (phonetic, Dvorak)", "kb_variants"), + tr("Russian (phonetic, French)", "kb_variants"), + tr("Russian (phonetic, Windows)", "kb_variants"), + tr("Russian (phonetic, YAZHERTY)", "kb_variants"), + tr("Russian (typewriter)", "kb_variants"), + tr("Russian (typewriter, legacy)", "kb_variants"), + tr("Saisiyat (Taiwan)", "kb_variants"), + tr("Samogitian", "kb_variants"), + tr("Sanskrit (KaGaPa, phonetic)", "kb_variants"), + tr("Serbian (Cyrillic, ZE and ZHE swapped)", "kb_variants"), + tr("Serbian (Cyrillic, with guillemets)", "kb_variants"), + tr("Serbian (Latin)", "kb_variants"), + tr("Serbian (Latin, QWERTY)", "kb_variants"), + tr("Serbian (Latin, Unicode)", "kb_variants"), + tr("Serbian (Latin, Unicode, QWERTY)", "kb_variants"), + tr("Serbian (Latin, with guillemets)", "kb_variants"), + tr("Serbian (Russia)", "kb_variants"), + tr("Serbo-Croatian (US)", "kb_variants"), + tr("Sicilian", "kb_variants"), + tr("Silesian", "kb_variants"), + tr("Sindhi", "kb_variants"), + tr("Sinhala (US)", "kb_variants"), + tr("Slovak (QWERTY)", "kb_variants"), + tr("Slovak (QWERTY, extended backslash)", "kb_variants"), + tr("Slovak (extended backslash)", "kb_variants"), + tr("Slovenian (US)", "kb_variants"), + tr("Slovenian (with guillemets)", "kb_variants"), + tr("Spanish (Dvorak)", "kb_variants"), + tr("Spanish (Latin American, Colemak for gaming)", "kb_variants"), + tr("Spanish (Latin American, Colemak)", "kb_variants"), + tr("Spanish (Latin American, Dvorak)", "kb_variants"), + tr("Spanish (Latin American, Sun dead keys)", "kb_variants"), + tr("Spanish (Latin American, dead tilde)", "kb_variants"), + tr("Spanish (Latin American, no dead keys)", "kb_variants"), + tr("Spanish (Macintosh)", "kb_variants"), + tr("Spanish (Sun dead keys)", "kb_variants"), + tr("Spanish (Windows)", "kb_variants"), + tr("Spanish (dead tilde)", "kb_variants"), + tr("Spanish (no dead keys)", "kb_variants"), + tr("Swedish (Dvorak)", "kb_variants"), + tr("Swedish (Dvorak, intl.)", "kb_variants"), + tr("Swedish (Macintosh)", "kb_variants"), + tr("Swedish (Svdvorak)", "kb_variants"), + tr("Swedish (US)", "kb_variants"), + tr("Swedish (no dead keys)", "kb_variants"), + tr("Swedish Sign Language", "kb_variants"), + tr("Syriac", "kb_variants"), + tr("Syriac (phonetic)", "kb_variants"), + tr("Taiwanese (indigenous)", "kb_variants"), + tr("Tajik (legacy)", "kb_variants"), + tr("Tamil (Inscript)", "kb_variants"), + tr("Tamil (Sri Lanka, TamilNet '99)", "kb_variants"), + tr("Tamil (Sri Lanka, TamilNet '99, TAB encoding)", "kb_variants"), + tr("Tamil (TamilNet '99 with Tamil numerals)", "kb_variants"), + tr("Tamil (TamilNet '99)", "kb_variants"), + tr("Tamil (TamilNet '99, TAB encoding)", "kb_variants"), + tr("Tamil (TamilNet '99, TSCII encoding)", "kb_variants"), + tr("Tatar", "kb_variants"), + tr("Telugu", "kb_variants"), + tr("Telugu (KaGaPa, phonetic)", "kb_variants"), + tr("Telugu (Sarala)", "kb_variants"), + tr("Thai (Pattachote)", "kb_variants"), + tr("Thai (TIS-820.2538)", "kb_variants"), + tr("Tibetan", "kb_variants"), + tr("Tibetan (with ASCII numerals)", "kb_variants"), + tr("Turkish (Alt-Q)", "kb_variants"), + tr("Turkish (F)", "kb_variants"), + tr("Turkish (Germany)", "kb_variants"), + tr("Turkish (Sun dead keys)", "kb_variants"), + tr("Turkish (intl., with dead keys)", "kb_variants"), + tr("Turkmen (Alt-Q)", "kb_variants"), + tr("Udmurt", "kb_variants"), + tr("Ukrainian (Windows)", "kb_variants"), + tr("Ukrainian (homophonic)", "kb_variants"), + tr("Ukrainian (legacy)", "kb_variants"), + tr("Ukrainian (phonetic)", "kb_variants"), + tr("Ukrainian (standard RSTU)", "kb_variants"), + tr("Ukrainian (typewriter)", "kb_variants"), + tr("Urdu (Pakistan, CRULP)", "kb_variants"), + tr("Urdu (Pakistan, NLA)", "kb_variants"), + tr("Urdu (Windows)", "kb_variants"), + tr("Urdu (alt. phonetic)", "kb_variants"), + tr("Urdu (phonetic)", "kb_variants"), + tr("Uyghur", "kb_variants"), + tr("Uzbek (Afghanistan)", "kb_variants"), + tr("Uzbek (Afghanistan, OLPC)", "kb_variants"), + tr("Uzbek (Latin)", "kb_variants"), + tr("Vietnamese (French)", "kb_variants"), + tr("Vietnamese (US)", "kb_variants"), + tr("Yakut", "kb_variants"), + tr("Yoruba", "kb_variants"), + QString() + }; +} +} + diff --git a/src/modules/keyboard/KeyboardLayoutModel.cpp b/src/modules/keyboard/KeyboardLayoutModel.cpp index 5b92678f6..34a1dec88 100644 --- a/src/modules/keyboard/KeyboardLayoutModel.cpp +++ b/src/modules/keyboard/KeyboardLayoutModel.cpp @@ -10,8 +10,136 @@ #include "KeyboardLayoutModel.h" +#include "utils/Logger.h" +#include "utils/RAII.h" +#include "utils/Retranslator.h" + +#include + #include +static QTranslator* s_kbtranslator = nullptr; + +void +retranslateKeyboardModels() +{ + if ( !s_kbtranslator ) + { + s_kbtranslator = new QTranslator; + } + (void)CalamaresUtils::loadTranslator( QLocale(), QStringLiteral( "kb_" ), s_kbtranslator ); +} + + +XKBListModel::XKBListModel( QObject* parent ) + : QAbstractListModel( parent ) +{ +} + +int +XKBListModel::rowCount( const QModelIndex& ) const +{ + return m_list.count(); +} + +QVariant +XKBListModel::data( const QModelIndex& index, int role ) const +{ + if ( !index.isValid() ) + { + return QVariant(); + } + if ( index.row() < 0 || index.row() >= m_list.count() ) + { + return QVariant(); + } + + const auto item = m_list.at( index.row() ); + switch ( role ) + { + case LabelRole: + if ( s_kbtranslator && !s_kbtranslator->isEmpty() && m_contextname ) + { + auto s = s_kbtranslator->translate( m_contextname, item.label.toUtf8().data() ); + if ( !s.isEmpty() ) + { + return s; + } + } + return item.label; + case KeyRole: + return item.key; + default: + return QVariant(); + } + __builtin_unreachable(); +} + +QString +XKBListModel::key( int index ) const +{ + if ( index < 0 || index >= m_list.count() ) + { + return QString(); + } + return m_list[ index ].key; +} + +QString +XKBListModel::label( int index ) const +{ + if ( index < 0 || index >= m_list.count() ) + { + return QString(); + } + return m_list[ index ].label; +} + +QHash< int, QByteArray > +XKBListModel::roleNames() const +{ + return { { Qt::DisplayRole, "label" }, { Qt::UserRole, "key" } }; +} + +void +XKBListModel::setCurrentIndex( int index ) +{ + if ( index >= m_list.count() || index < 0 ) + { + return; + } + if ( m_currentIndex != index ) + { + m_currentIndex = index; + emit currentIndexChanged( m_currentIndex ); + } +} + +KeyboardModelsModel::KeyboardModelsModel( QObject* parent ) + : XKBListModel( parent ) +{ + m_contextname = "kb_models"; + + // The models map is from human-readable names (!) to xkb identifier + const auto models = KeyboardGlobal::getKeyboardModels(); + m_list.reserve( models.count() ); + int index = 0; + for ( const auto& key : models.keys() ) + { + // So here *key* is the key in the map, which is the human-readable thing, + // while the struct fields are xkb-id, and human-readable + m_list << ModelInfo { models[ key ], key }; + if ( models[ key ] == "pc105" ) + { + m_defaultPC105 = index; + } + index++; + } + + cDebug() << "Loaded" << m_list.count() << "keyboard models"; + setCurrentIndex(); // If pc105 was seen, select it now +} + KeyboardLayoutModel::KeyboardLayoutModel( QObject* parent ) : QAbstractListModel( parent ) @@ -38,7 +166,18 @@ KeyboardLayoutModel::data( const QModelIndex& index, int role ) const switch ( role ) { case Qt::DisplayRole: - return m_layouts.at( index.row() ).second.description; + { + auto description = m_layouts.at( index.row() ).second.description; + if ( s_kbtranslator && !s_kbtranslator->isEmpty() ) + { + auto s = s_kbtranslator->translate( "kb_layouts", description.toUtf8().data() ); + if ( !s.isEmpty() ) + { + return s; + } + } + return description; + } case KeyboardVariantsRole: return QVariant::fromValue( m_layouts.at( index.row() ).second.variants ); case KeyboardLayoutKeyRole: @@ -59,6 +198,16 @@ KeyboardLayoutModel::item( const int& index ) const return m_layouts.at( index ); } +QString +KeyboardLayoutModel::key( int index ) const +{ + if ( index >= m_layouts.count() || index < 0 ) + { + return QString(); + } + return m_layouts.at( index ).first; +} + void KeyboardLayoutModel::init() { @@ -83,15 +232,18 @@ KeyboardLayoutModel::roleNames() const } void -KeyboardLayoutModel::setCurrentIndex( const int& index ) +KeyboardLayoutModel::setCurrentIndex( int index ) { if ( index >= m_layouts.count() || index < 0 ) { return; } - m_currentIndex = index; - emit currentIndexChanged( m_currentIndex ); + if ( m_currentIndex != index ) + { + m_currentIndex = index; + emit currentIndexChanged( m_currentIndex ); + } } int @@ -99,3 +251,24 @@ KeyboardLayoutModel::currentIndex() const { return m_currentIndex; } + + +KeyboardVariantsModel::KeyboardVariantsModel( QObject* parent ) + : XKBListModel( parent ) +{ + m_contextname = "kb_variants"; +} + +void +KeyboardVariantsModel::setVariants( QMap< QString, QString > variants ) +{ + beginResetModel(); + m_list.clear(); + m_list.reserve( variants.count() ); + for ( const auto& key : variants.keys() ) + { + m_list << ModelInfo { variants[ key ], key }; + } + m_currentIndex = -1; + endResetModel(); +} diff --git a/src/modules/keyboard/KeyboardLayoutModel.h b/src/modules/keyboard/KeyboardLayoutModel.h index f4699c9f8..c2306c001 100644 --- a/src/modules/keyboard/KeyboardLayoutModel.h +++ b/src/modules/keyboard/KeyboardLayoutModel.h @@ -17,6 +17,85 @@ #include #include +/** @brief A list model with an xkb key and a human-readable string + * + * This model acts like it has a single selection, as well. + */ +class XKBListModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY( int currentIndex WRITE setCurrentIndex READ currentIndex NOTIFY currentIndexChanged ) + +public: + enum + { + LabelRole = Qt::DisplayRole, ///< Human-readable + KeyRole = Qt::UserRole ///< xkb identifier + }; + + explicit XKBListModel( QObject* parent = nullptr ); + + int rowCount( const QModelIndex& = QModelIndex() ) const override; + QVariant data( const QModelIndex& index, int role ) const override; + /** @brief xkb key for a given index (row) + * + * This is like calling data( QModelIndex( index ), KeyRole ).toString(), + * but shorter and faster. Can return an empty string if index is invalid. + */ + QString key( int index ) const; + + /** @brief human-readable label for a given index (row) + * + * This is like calling data( QModelIndex( index ), LabelRole ).toString(), + * but shorter and faster. Can return an empty string if index is invalid. + */ + QString label( int index ) const; + + QHash< int, QByteArray > roleNames() const override; + + void setCurrentIndex( int index ); + int currentIndex() const { return m_currentIndex; } + +signals: + void currentIndexChanged( int index ); + +protected: + struct ModelInfo + { + /// XKB identifier + QString key; + /// Human-readable + QString label; + }; + QVector< ModelInfo > m_list; + int m_currentIndex = -1; + const char* m_contextname = nullptr; +}; + + +/** @brief A list model of the physical keyboard formats ("models" in xkb) + * + * This model acts like it has a single selection, as well. + */ +class KeyboardModelsModel : public XKBListModel +{ + Q_OBJECT + +public: + explicit KeyboardModelsModel( QObject* parent = nullptr ); + + /// @brief Set the index back to PC105 (the default physical model) + void setCurrentIndex() { XKBListModel::setCurrentIndex( m_defaultPC105 ); } + +private: + int m_defaultPC105 = -1; ///< The index of pc105, if there is one +}; + +/** @brief A list of keyboard layouts (arrangements of keycaps) + * + * Layouts can have a list of associated Variants, so this + * is slightly more complicated than the "regular" XKBListModel. + */ class KeyboardLayoutModel : public QAbstractListModel { Q_OBJECT @@ -35,10 +114,17 @@ public: QVariant data( const QModelIndex& index, int role ) const override; - void setCurrentIndex( const int& index ); + void setCurrentIndex( int index ); int currentIndex() const; const QPair< QString, KeyboardGlobal::KeyboardInfo > item( const int& index ) const; + /** @brief xkb key for a given index (row) + * + * This is like calling data( QModelIndex( index ), KeyboardLayoutKeyRole ).toString(), + * but shorter and faster. Can return an empty string if index is invalid. + */ + QString key( int index ) const; + protected: QHash< int, QByteArray > roleNames() const override; @@ -51,4 +137,24 @@ signals: void currentIndexChanged( int index ); }; +/** @brief A list of variants (xkb id and human-readable) + * + * The variants that are available depend on the Layout that is used, + * so the `setVariants()` function can be used to update the variants + * when the two models are related. + */ +class KeyboardVariantsModel : public XKBListModel +{ + Q_OBJECT + +public: + explicit KeyboardVariantsModel( QObject* parent = nullptr ); + + void setVariants( QMap< QString, QString > variants ); +}; + +/** @brief Adjust to changes in application language. + */ +void retranslateKeyboardModels(); + #endif // KEYBOARDLAYOUTMODEL_H diff --git a/src/modules/keyboard/KeyboardPage.cpp b/src/modules/keyboard/KeyboardPage.cpp index 07c5cf763..5044d9bb6 100644 --- a/src/modules/keyboard/KeyboardPage.cpp +++ b/src/modules/keyboard/KeyboardPage.cpp @@ -15,6 +15,7 @@ #include "KeyboardPage.h" +#include "Config.h" #include "KeyboardLayoutModel.h" #include "SetKeyboardLayoutJob.h" #include "keyboardwidget/keyboardpreview.h" @@ -40,451 +41,77 @@ public: LayoutItem::~LayoutItem() {} -static QPersistentModelIndex -findLayout( const KeyboardLayoutModel* klm, const QString& currentLayout ) -{ - QPersistentModelIndex currentLayoutItem; - - for ( int i = 0; i < klm->rowCount(); ++i ) - { - QModelIndex idx = klm->index( i ); - if ( idx.isValid() && idx.data( KeyboardLayoutModel::KeyboardLayoutKeyRole ).toString() == currentLayout ) - { - currentLayoutItem = idx; - } - } - - return currentLayoutItem; -} - -KeyboardPage::KeyboardPage( QWidget* parent ) +KeyboardPage::KeyboardPage( Config* config, QWidget* parent ) : QWidget( parent ) , ui( new Ui::Page_Keyboard ) , m_keyboardPreview( new KeyBoardPreview( this ) ) - , m_defaultIndex( 0 ) + , m_config( config ) { ui->setupUi( this ); // Keyboard Preview ui->KBPreviewLayout->addWidget( m_keyboardPreview ); - m_setxkbmapTimer.setSingleShot( true ); + { + auto* model = config->keyboardModels(); + model->setCurrentIndex(); // To default PC105 + ui->physicalModelSelector->setModel( model ); + ui->physicalModelSelector->setCurrentIndex( model->currentIndex() ); + } + { + auto* model = config->keyboardLayouts(); + ui->layoutSelector->setModel( model ); + ui->layoutSelector->setCurrentIndex( model->index( model->currentIndex() ) ); + } + { + auto* model = config->keyboardVariants(); + ui->variantSelector->setModel( model ); + ui->variantSelector->setCurrentIndex( model->index( model->currentIndex() ) ); + cDebug() << "Variants now" << model->rowCount() << model->currentIndex(); + } - // Connect signals and slots - connect( ui->listVariant, &QListWidget::currentItemChanged, this, &KeyboardPage::onListVariantCurrentItemChanged ); - - connect( - ui->buttonRestore, &QPushButton::clicked, [this] { ui->comboBoxModel->setCurrentIndex( m_defaultIndex ); } ); - - connect( ui->comboBoxModel, &QComboBox::currentTextChanged, [this]( const QString& text ) { - QString model = m_models.value( text, "pc105" ); - - // Set Xorg keyboard model - QProcess::execute( "setxkbmap", QStringList { "-model", model } ); + connect( ui->buttonRestore, &QPushButton::clicked, [ config = config ] { + config->keyboardModels()->setCurrentIndex(); } ); - CALAMARES_RETRANSLATE( ui->retranslateUi( this ); ) -} + connect( ui->physicalModelSelector, + QOverload< int >::of( &QComboBox::currentIndexChanged ), + config->keyboardModels(), + QOverload< int >::of( &XKBListModel::setCurrentIndex ) ); + connect( config->keyboardModels(), + &KeyboardModelsModel::currentIndexChanged, + ui->physicalModelSelector, + &QComboBox::setCurrentIndex ); + connect( + ui->layoutSelector->selectionModel(), + &QItemSelectionModel::currentChanged, + [ this ]( const QModelIndex& current ) { m_config->keyboardLayouts()->setCurrentIndex( current.row() ); } ); + connect( config->keyboardLayouts(), &KeyboardLayoutModel::currentIndexChanged, [ this ]( int index ) { + ui->layoutSelector->setCurrentIndex( m_config->keyboardLayouts()->index( index ) ); + m_keyboardPreview->setLayout( m_config->keyboardLayouts()->key( index ) ); + m_keyboardPreview->setVariant( m_config->keyboardVariants()->key( m_config->keyboardVariants()->currentIndex() ) ); + } ); + + connect( + ui->variantSelector->selectionModel(), + &QItemSelectionModel::currentChanged, + [ this ]( const QModelIndex& current ) { m_config->keyboardVariants()->setCurrentIndex( current.row() ); } ); + connect( config->keyboardVariants(), &KeyboardVariantsModel::currentIndexChanged, [ this ]( int index ) { + ui->variantSelector->setCurrentIndex( m_config->keyboardVariants()->index( index ) ); + m_keyboardPreview->setVariant( m_config->keyboardVariants()->key( index ) ); + } ); + CALAMARES_RETRANSLATE_SLOT( &KeyboardPage::retranslate ) +} KeyboardPage::~KeyboardPage() { delete ui; } - void -KeyboardPage::init() +KeyboardPage::retranslate() { - //### Detect current keyboard layout and variant - QString currentLayout; - QString currentVariant; - QProcess process; - process.start( "setxkbmap", QStringList() << "-print" ); - - if ( process.waitForFinished() ) - { - const QStringList list = QString( process.readAll() ).split( "\n", SplitSkipEmptyParts ); - - for ( QString line : list ) - { - line = line.trimmed(); - if ( !line.startsWith( "xkb_symbols" ) ) - { - continue; - } - - line = line.remove( "}" ).remove( "{" ).remove( ";" ); - line = line.mid( line.indexOf( "\"" ) + 1 ); - - QStringList split = line.split( "+", SplitSkipEmptyParts ); - if ( split.size() >= 2 ) - { - currentLayout = split.at( 1 ); - - if ( currentLayout.contains( "(" ) ) - { - int parenthesisIndex = currentLayout.indexOf( "(" ); - currentVariant = currentLayout.mid( parenthesisIndex + 1 ).trimmed(); - currentVariant.chop( 1 ); - currentLayout = currentLayout.mid( 0, parenthesisIndex ).trimmed(); - } - - break; - } - } - } - - //### Models - m_models = KeyboardGlobal::getKeyboardModels(); - QMapIterator< QString, QString > mi( m_models ); - - ui->comboBoxModel->blockSignals( true ); - - while ( mi.hasNext() ) - { - mi.next(); - - if ( mi.value() == "pc105" ) - { - m_defaultIndex = ui->comboBoxModel->count(); - } - - ui->comboBoxModel->addItem( mi.key() ); - } - - ui->comboBoxModel->blockSignals( false ); - - // Set to default value pc105 - ui->comboBoxModel->setCurrentIndex( m_defaultIndex ); - - - //### Layouts and Variants - - KeyboardLayoutModel* klm = new KeyboardLayoutModel( this ); - ui->listLayout->setModel( klm ); - connect( ui->listLayout->selectionModel(), - &QItemSelectionModel::currentChanged, - this, - &KeyboardPage::onListLayoutCurrentItemChanged ); - - // Block signals - ui->listLayout->blockSignals( true ); - - QPersistentModelIndex currentLayoutItem = findLayout( klm, currentLayout ); - if ( !currentLayoutItem.isValid() && ( ( currentLayout == "latin" ) || ( currentLayout == "pc" ) ) ) - { - currentLayout = "us"; - currentLayoutItem = findLayout( klm, currentLayout ); - } - - // Set current layout and variant - if ( currentLayoutItem.isValid() ) - { - ui->listLayout->setCurrentIndex( currentLayoutItem ); - updateVariants( currentLayoutItem, currentVariant ); - } - - // Unblock signals - ui->listLayout->blockSignals( false ); - - // Default to the first available layout if none was set - // Do this after unblocking signals so we get the default variant handling. - if ( !currentLayoutItem.isValid() && klm->rowCount() > 0 ) - { - ui->listLayout->setCurrentIndex( klm->index( 0 ) ); - } -} - - -QString -KeyboardPage::prettyStatus() const -{ - QString status; - status += tr( "Set keyboard model to %1.
" ).arg( ui->comboBoxModel->currentText() ); - - QString layout = ui->listLayout->currentIndex().data().toString(); - QString variant = ui->listVariant->currentItem() ? ui->listVariant->currentItem()->text() : QString( "" ); - status += tr( "Set keyboard layout to %1/%2." ).arg( layout, variant ); - - return status; -} - - -QList< Calamares::job_ptr > -KeyboardPage::createJobs( const QString& xOrgConfFileName, - const QString& convertedKeymapPath, - bool writeEtcDefaultKeyboard ) -{ - QList< Calamares::job_ptr > list; - QString selectedModel = m_models.value( ui->comboBoxModel->currentText(), "pc105" ); - - Calamares::Job* j = new SetKeyboardLayoutJob( selectedModel, - m_selectedLayout, - m_selectedVariant, - xOrgConfFileName, - convertedKeymapPath, - writeEtcDefaultKeyboard ); - list.append( Calamares::job_ptr( j ) ); - - return list; -} - - -void -KeyboardPage::guessLayout( const QStringList& langParts ) -{ - const KeyboardLayoutModel* klm = dynamic_cast< KeyboardLayoutModel* >( ui->listLayout->model() ); - bool foundCountryPart = false; - for ( auto countryPart = langParts.rbegin(); !foundCountryPart && countryPart != langParts.rend(); ++countryPart ) - { - cDebug() << Logger::SubEntry << "looking for locale part" << *countryPart; - for ( int i = 0; i < klm->rowCount(); ++i ) - { - QModelIndex idx = klm->index( i ); - QString name - = idx.isValid() ? idx.data( KeyboardLayoutModel::KeyboardLayoutKeyRole ).toString() : QString(); - if ( idx.isValid() && ( name.compare( *countryPart, Qt::CaseInsensitive ) == 0 ) ) - { - cDebug() << Logger::SubEntry << "matched" << name; - ui->listLayout->setCurrentIndex( idx ); - foundCountryPart = true; - break; - } - } - if ( foundCountryPart ) - { - ++countryPart; - if ( countryPart != langParts.rend() ) - { - cDebug() << "Next level:" << *countryPart; - for ( int variantnumber = 0; variantnumber < ui->listVariant->count(); ++variantnumber ) - { - LayoutItem* variantdata = dynamic_cast< LayoutItem* >( ui->listVariant->item( variantnumber ) ); - if ( variantdata && ( variantdata->data.compare( *countryPart, Qt::CaseInsensitive ) == 0 ) ) - { - ui->listVariant->setCurrentItem( variantdata ); - cDebug() << Logger::SubEntry << "matched variant" << variantdata->data << ' ' - << variantdata->text(); - } - } - } - } - } -} - - -void -KeyboardPage::onActivate() -{ - /* Guessing a keyboard layout based on the locale means - * mapping between language identifiers in _ - * format to keyboard mappings, which are _ - * format; in addition, some countries have multiple languages, - * so fr_BE and nl_BE want different layouts (both Belgian) - * and sometimes the language-country name doesn't match the - * keyboard-country name at all (e.g. Ellas vs. Greek). - * - * This is a table of language-to-keyboard mappings. The - * language identifier is the key, while the value is - * a string that is used instead of the real language - * identifier in guessing -- so it should be something - * like _. - */ - static constexpr char arabic[] = "ara"; - static const auto specialCaseMap = QMap< std::string, std::string >( { - /* Most Arab countries map to Arabic keyboard (Default) */ - { "ar_AE", arabic }, - { "ar_BH", arabic }, - { "ar_DZ", arabic }, - { "ar_EG", arabic }, - { "ar_IN", arabic }, - { "ar_IQ", arabic }, - { "ar_JO", arabic }, - { "ar_KW", arabic }, - { "ar_LB", arabic }, - { "ar_LY", arabic }, - /* Not Morocco: use layout ma */ - { "ar_OM", arabic }, - { "ar_QA", arabic }, - { "ar_SA", arabic }, - { "ar_SD", arabic }, - { "ar_SS", arabic }, - /* Not Syria: use layout sy */ - { "ar_TN", arabic }, - { "ar_YE", arabic }, - { "ca_ES", "cat_ES" }, /* Catalan */ - { "as_ES", "ast_ES" }, /* Asturian */ - { "en_CA", "us" }, /* Canadian English */ - { "el_CY", "gr" }, /* Greek in Cyprus */ - { "el_GR", "gr" }, /* Greek in Greeze */ - { "ig_NG", "igbo_NG" }, /* Igbo in Nigeria */ - { "ha_NG", "hausa_NG" } /* Hausa */ - } ); - - ui->listLayout->setFocus(); - - // Try to preselect a layout, depending on language and locale - Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); - QString lang = gs->value( "localeConf" ).toMap().value( "LANG" ).toString(); - - cDebug() << "Got locale language" << lang; - if ( !lang.isEmpty() ) - { - // Chop off .codeset and @modifier - int index = lang.indexOf( '.' ); - if ( index >= 0 ) - { - lang.truncate( index ); - } - index = lang.indexOf( '@' ); - if ( index >= 0 ) - { - lang.truncate( index ); - } - - lang.replace( '-', '_' ); // Normalize separators - } - if ( !lang.isEmpty() ) - { - std::string lang_s = lang.toStdString(); - if ( specialCaseMap.contains( lang_s ) ) - { - QString newLang = QString::fromStdString( specialCaseMap.value( lang_s ) ); - cDebug() << Logger::SubEntry << "special case language" << lang << "becomes" << newLang; - lang = newLang; - } - } - if ( !lang.isEmpty() ) - { - const auto langParts = lang.split( '_', SplitSkipEmptyParts ); - - // Note that this his string is not fit for display purposes! - // It doesn't come from QLocale::nativeCountryName. - QString country = QLocale::countryToString( QLocale( lang ).country() ); - cDebug() << Logger::SubEntry << "extracted country" << country << "::" << langParts; - - guessLayout( langParts ); - } -} - - -void -KeyboardPage::finalize() -{ - Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); - if ( !m_selectedLayout.isEmpty() ) - { - gs->insert( "keyboardLayout", m_selectedLayout ); - gs->insert( "keyboardVariant", m_selectedVariant ); //empty means default variant - } - - //FIXME: also store keyboard model for something? -} - - -void -KeyboardPage::updateVariants( const QPersistentModelIndex& currentItem, QString currentVariant ) -{ - // Block signals - ui->listVariant->blockSignals( true ); - - QMap< QString, QString > variants - = currentItem.data( KeyboardLayoutModel::KeyboardVariantsRole ).value< QMap< QString, QString > >(); - QMapIterator< QString, QString > li( variants ); - LayoutItem* defaultItem = nullptr; - - ui->listVariant->clear(); - - while ( li.hasNext() ) - { - li.next(); - - LayoutItem* item = new LayoutItem(); - item->setText( li.key() ); - item->data = li.value(); - ui->listVariant->addItem( item ); - - // currentVariant defaults to QString(). It is only non-empty during the - // initial setup. - if ( li.value() == currentVariant ) - { - defaultItem = item; - } - } - - // Unblock signals - ui->listVariant->blockSignals( false ); - - // Set to default value - if ( defaultItem ) - { - ui->listVariant->setCurrentItem( defaultItem ); - } -} - - -void -KeyboardPage::onListLayoutCurrentItemChanged( const QModelIndex& current, const QModelIndex& previous ) -{ - Q_UNUSED( previous ) - if ( !current.isValid() ) - { - return; - } - - updateVariants( QPersistentModelIndex( current ) ); -} - -/* Returns stringlist with suitable setxkbmap command-line arguments - * to set the given @p layout and @p variant. - */ -static inline QStringList -xkbmap_args( const QString& layout, const QString& variant ) -{ - QStringList r { "-layout", layout }; - if ( !variant.isEmpty() ) - { - r << "-variant" << variant; - } - return r; -} - -void -KeyboardPage::onListVariantCurrentItemChanged( QListWidgetItem* current, QListWidgetItem* previous ) -{ - Q_UNUSED( previous ) - - QPersistentModelIndex layoutIndex = ui->listLayout->currentIndex(); - LayoutItem* variantItem = dynamic_cast< LayoutItem* >( current ); - - if ( !layoutIndex.isValid() || !variantItem ) - { - return; - } - - QString layout = layoutIndex.data( KeyboardLayoutModel::KeyboardLayoutKeyRole ).toString(); - QString variant = variantItem->data; - - m_keyboardPreview->setLayout( layout ); - m_keyboardPreview->setVariant( variant ); - - //emit checkReady(); - - // Set Xorg keyboard layout - if ( m_setxkbmapTimer.isActive() ) - { - m_setxkbmapTimer.stop(); - m_setxkbmapTimer.disconnect( this ); - } - - connect( &m_setxkbmapTimer, &QTimer::timeout, this, [=] { - QProcess::execute( "setxkbmap", xkbmap_args( layout, variant ) ); - cDebug() << "xkbmap selection changed to: " << layout << '-' << variant; - m_setxkbmapTimer.disconnect( this ); - } ); - m_setxkbmapTimer.start( QApplication::keyboardInputInterval() ); - - m_selectedLayout = layout; - m_selectedVariant = variant; + ui->retranslateUi( this ); + m_config->retranslate(); } diff --git a/src/modules/keyboard/KeyboardPage.h b/src/modules/keyboard/KeyboardPage.h index 4faeebd57..1c644cc08 100644 --- a/src/modules/keyboard/KeyboardPage.h +++ b/src/modules/keyboard/KeyboardPage.h @@ -27,42 +27,22 @@ namespace Ui class Page_Keyboard; } +class Config; class KeyBoardPreview; class KeyboardPage : public QWidget { Q_OBJECT public: - explicit KeyboardPage( QWidget* parent = nullptr ); + explicit KeyboardPage( Config* config, QWidget* parent = nullptr ); ~KeyboardPage() override; - void init(); - - QString prettyStatus() const; - - Calamares::JobList - createJobs( const QString& xOrgConfFileName, const QString& convertedKeymapPath, bool writeEtcDefaultKeyboard ); - - void onActivate(); - void finalize(); - -protected slots: - void onListLayoutCurrentItemChanged( const QModelIndex& current, const QModelIndex& previous ); - void onListVariantCurrentItemChanged( QListWidgetItem* current, QListWidgetItem* previous ); + void retranslate(); private: - /// Guess a layout based on the split-apart locale - void guessLayout( const QStringList& langParts ); - void updateVariants( const QPersistentModelIndex& currentItem, QString currentVariant = QString() ); - Ui::Page_Keyboard* ui; KeyBoardPreview* m_keyboardPreview; - int m_defaultIndex; - QMap< QString, QString > m_models; - - QString m_selectedLayout; - QString m_selectedVariant; - QTimer m_setxkbmapTimer; + Config* m_config; }; #endif // KEYBOARDPAGE_H diff --git a/src/modules/keyboard/KeyboardPage.ui b/src/modules/keyboard/KeyboardPage.ui index f7e430a04..f7592fc6a 100644 --- a/src/modules/keyboard/KeyboardPage.ui +++ b/src/modules/keyboard/KeyboardPage.ui @@ -76,7 +76,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - + 0 @@ -110,10 +110,10 @@ SPDX-License-Identifier: GPL-3.0-or-later 9 - + - + @@ -139,9 +139,9 @@ SPDX-License-Identifier: GPL-3.0-or-later - comboBoxModel - listLayout - listVariant + physicalModelSelector + layoutSelector + variantSelector LE_TestKeyboard buttonRestore diff --git a/src/modules/keyboard/KeyboardViewStep.cpp b/src/modules/keyboard/KeyboardViewStep.cpp index 55402fd14..d1eb3eb68 100644 --- a/src/modules/keyboard/KeyboardViewStep.cpp +++ b/src/modules/keyboard/KeyboardViewStep.cpp @@ -9,24 +9,21 @@ #include "KeyboardViewStep.h" +#include "Config.h" #include "KeyboardPage.h" #include "GlobalStorage.h" #include "JobQueue.h" -#include "utils/Variant.h" - CALAMARES_PLUGIN_FACTORY_DEFINITION( KeyboardViewStepFactory, registerPlugin< KeyboardViewStep >(); ) KeyboardViewStep::KeyboardViewStep( QObject* parent ) : Calamares::ViewStep( parent ) - , m_widget( new KeyboardPage() ) - , m_nextEnabled( false ) - , m_writeEtcDefaultKeyboard( true ) + , m_config( new Config( this ) ) + , m_widget( new KeyboardPage( m_config ) ) { - m_widget->init(); - m_nextEnabled = true; - emit nextStatusChanged( m_nextEnabled ); + m_config->detectCurrentKeyboardLayout(); + emit nextStatusChanged( true ); } @@ -49,7 +46,7 @@ KeyboardViewStep::prettyName() const QString KeyboardViewStep::prettyStatus() const { - return m_prettyStatus; + return m_config->prettyStatus(); } @@ -63,7 +60,7 @@ KeyboardViewStep::widget() bool KeyboardViewStep::isNextEnabled() const { - return m_nextEnabled; + return true; } @@ -91,60 +88,26 @@ KeyboardViewStep::isAtEnd() const QList< Calamares::job_ptr > KeyboardViewStep::jobs() const { - return m_jobs; + return m_config->createJobs(); } void KeyboardViewStep::onActivate() { - m_widget->onActivate(); + m_config->onActivate(); } void KeyboardViewStep::onLeave() { - m_widget->finalize(); - m_jobs = m_widget->createJobs( m_xOrgConfFileName, m_convertedKeymapPath, m_writeEtcDefaultKeyboard ); - m_prettyStatus = m_widget->prettyStatus(); + m_config->finalize(); } void KeyboardViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { - using namespace CalamaresUtils; - - if ( configurationMap.contains( "xOrgConfFileName" ) - && configurationMap.value( "xOrgConfFileName" ).type() == QVariant::String - && !getString( configurationMap, "xOrgConfFileName" ).isEmpty() ) - { - m_xOrgConfFileName = getString( configurationMap, "xOrgConfFileName" ); - } - else - { - m_xOrgConfFileName = "00-keyboard.conf"; - } - - if ( configurationMap.contains( "convertedKeymapPath" ) - && configurationMap.value( "convertedKeymapPath" ).type() == QVariant::String - && !getString( configurationMap, "convertedKeymapPath" ).isEmpty() ) - { - m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" ); - } - else - { - m_convertedKeymapPath = QString(); - } - - if ( configurationMap.contains( "writeEtcDefaultKeyboard" ) - && configurationMap.value( "writeEtcDefaultKeyboard" ).type() == QVariant::Bool ) - { - m_writeEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true ); - } - else - { - m_writeEtcDefaultKeyboard = true; - } + m_config->setConfigurationMap( configurationMap ); } diff --git a/src/modules/keyboard/KeyboardViewStep.h b/src/modules/keyboard/KeyboardViewStep.h index aa9a1d335..902b888fd 100644 --- a/src/modules/keyboard/KeyboardViewStep.h +++ b/src/modules/keyboard/KeyboardViewStep.h @@ -17,6 +17,7 @@ #include +class Config; class KeyboardPage; class PLUGINDLLEXPORT KeyboardViewStep : public Calamares::ViewStep @@ -46,15 +47,8 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ) override; private: + Config* m_config; KeyboardPage* m_widget; - bool m_nextEnabled; - QString m_prettyStatus; - - QString m_xOrgConfFileName; - QString m_convertedKeymapPath; - bool m_writeEtcDefaultKeyboard; - - Calamares::JobList m_jobs; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( KeyboardViewStepFactory ) diff --git a/src/modules/keyboard/SetKeyboardLayoutJob.cpp b/src/modules/keyboard/SetKeyboardLayoutJob.cpp index cabe0b5c0..c80d84e7d 100644 --- a/src/modules/keyboard/SetKeyboardLayoutJob.cpp +++ b/src/modules/keyboard/SetKeyboardLayoutJob.cpp @@ -33,6 +33,7 @@ SetKeyboardLayoutJob::SetKeyboardLayoutJob( const QString& model, const QString& layout, const QString& variant, + const AdditionalLayoutInfo& additionalLayoutInfo, const QString& xOrgConfFileName, const QString& convertedKeymapPath, bool writeEtcDefaultKeyboard ) @@ -40,6 +41,7 @@ SetKeyboardLayoutJob::SetKeyboardLayoutJob( const QString& model, , m_model( model ) , m_layout( layout ) , m_variant( variant ) + , m_additionalLayoutInfo( additionalLayoutInfo ) , m_xOrgConfFileName( xOrgConfFileName ) , m_convertedKeymapPath( convertedKeymapPath ) , m_writeEtcDefaultKeyboard( writeEtcDefaultKeyboard ) @@ -177,6 +179,8 @@ SetKeyboardLayoutJob::findLegacyKeymap() const bool SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const QString& convertedKeymapPath ) const { + cDebug() << "Writing vconsole data to" << vconsoleConfPath; + QString keymap = findConvertedKeymap( convertedKeymapPath ); if ( keymap.isEmpty() ) { @@ -203,15 +207,20 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const file.close(); if ( stream.status() != QTextStream::Ok ) { + cError() << "Could not read lines from" << file.fileName(); return false; } } // Write out the existing lines and replace the KEYMAP= line - file.open( QIODevice::WriteOnly | QIODevice::Text ); + if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + { + cError() << "Could not open" << file.fileName() << "for writing."; + return false; + } QTextStream stream( &file ); bool found = false; - foreach ( const QString& existingLine, existingLines ) + for ( const QString& existingLine : qAsConst( existingLines ) ) { if ( existingLine.trimmed().startsWith( "KEYMAP=" ) ) { @@ -231,7 +240,7 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const stream.flush(); file.close(); - cDebug() << "Written KEYMAP=" << keymap << "to vconsole.conf"; + cDebug() << Logger::SubEntry << "Written KEYMAP=" << keymap << "to vconsole.conf" << stream.status(); return ( stream.status() == QTextStream::Ok ); } @@ -240,8 +249,14 @@ SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath, const bool SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const { + cDebug() << "Writing X11 configuration to" << keyboardConfPath; + QFile file( keyboardConfPath ); - file.open( QIODevice::WriteOnly | QIODevice::Text ); + if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + { + cError() << "Could not open" << file.fileName() << "for writing."; + return false; + } QTextStream stream( &file ); stream << "# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" @@ -250,19 +265,34 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const " Identifier \"system-keyboard\"\n" " MatchIsKeyboard \"on\"\n"; - if ( !m_layout.isEmpty() ) - { - stream << " Option \"XkbLayout\" \"" << m_layout << "\"\n"; - } - if ( !m_model.isEmpty() ) + if ( m_additionalLayoutInfo.additionalLayout.isEmpty() ) { - stream << " Option \"XkbModel\" \"" << m_model << "\"\n"; - } + if ( !m_layout.isEmpty() ) + { + stream << " Option \"XkbLayout\" \"" << m_layout << "\"\n"; + } - if ( !m_variant.isEmpty() ) + if ( !m_variant.isEmpty() ) + { + stream << " Option \"XkbVariant\" \"" << m_variant << "\"\n"; + } + } + else { - stream << " Option \"XkbVariant\" \"" << m_variant << "\"\n"; + if ( !m_layout.isEmpty() ) + { + stream << " Option \"XkbLayout\" \"" << m_additionalLayoutInfo.additionalLayout << "," << m_layout + << "\"\n"; + } + + if ( !m_variant.isEmpty() ) + { + stream << " Option \"XkbVariant\" \"" << m_additionalLayoutInfo.additionalVariant << "," << m_variant + << "\"\n"; + } + + stream << " Option \"XkbOptions\" \"" << m_additionalLayoutInfo.groupSwitcher << "\"\n"; } stream << "EndSection\n"; @@ -270,8 +300,8 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const file.close(); - cDebug() << "Written XkbLayout" << m_layout << "; XkbModel" << m_model << "; XkbVariant" << m_variant - << "to X.org file" << keyboardConfPath; + cDebug() << Logger::SubEntry << "Written XkbLayout" << m_layout << "; XkbModel" << m_model << "; XkbVariant" + << m_variant << "to X.org file" << keyboardConfPath << stream.status(); return ( stream.status() == QTextStream::Ok ); } @@ -280,8 +310,14 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const bool SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPath ) const { + cDebug() << "Writing default keyboard data to" << defaultKeyboardPath; + QFile file( defaultKeyboardPath ); - file.open( QIODevice::WriteOnly | QIODevice::Text ); + if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + { + cError() << "Could not open" << defaultKeyboardPath << "for writing"; + return false; + } QTextStream stream( &file ); stream << "# KEYBOARD CONFIGURATION FILE\n\n" @@ -296,8 +332,8 @@ SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPa file.close(); - cDebug() << "Written XKBMODEL" << m_model << "; XKBLAYOUT" << m_layout << "; XKBVARIANT" << m_variant - << "to /etc/default/keyboard file" << defaultKeyboardPath; + cDebug() << Logger::SubEntry << "Written XKBMODEL" << m_model << "; XKBLAYOUT" << m_layout << "; XKBVARIANT" + << m_variant << "to /etc/default/keyboard file" << defaultKeyboardPath << stream.status(); return ( stream.status() == QTextStream::Ok ); } @@ -312,60 +348,72 @@ SetKeyboardLayoutJob::exec() Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QDir destDir( gs->value( "rootMountPoint" ).toString() ); - // Get the path to the destination's /etc/vconsole.conf - QString vconsoleConfPath = destDir.absoluteFilePath( "etc/vconsole.conf" ); - - // Get the path to the destination's /etc/X11/xorg.conf.d/00-keyboard.conf - QString xorgConfDPath; - QString keyboardConfPath; - if ( QDir::isAbsolutePath( m_xOrgConfFileName ) ) { - keyboardConfPath = m_xOrgConfFileName; - while ( keyboardConfPath.startsWith( '/' ) ) + // Get the path to the destination's /etc/vconsole.conf + QString vconsoleConfPath = destDir.absoluteFilePath( "etc/vconsole.conf" ); + + // Get the path to the destination's path to the converted key mappings + QString convertedKeymapPath = m_convertedKeymapPath; + if ( !convertedKeymapPath.isEmpty() ) { - keyboardConfPath.remove( 0, 1 ); + while ( convertedKeymapPath.startsWith( '/' ) ) + { + convertedKeymapPath.remove( 0, 1 ); + } + convertedKeymapPath = destDir.absoluteFilePath( convertedKeymapPath ); } - keyboardConfPath = destDir.absoluteFilePath( keyboardConfPath ); - xorgConfDPath = QFileInfo( keyboardConfPath ).path(); - } - else - { - xorgConfDPath = destDir.absoluteFilePath( "etc/X11/xorg.conf.d" ); - keyboardConfPath = QDir( xorgConfDPath ).absoluteFilePath( m_xOrgConfFileName ); - } - destDir.mkpath( xorgConfDPath ); - QString defaultKeyboardPath; - if ( QDir( destDir.absoluteFilePath( "etc/default" ) ).exists() ) - { - defaultKeyboardPath = destDir.absoluteFilePath( "etc/default/keyboard" ); - } - - // Get the path to the destination's path to the converted key mappings - QString convertedKeymapPath = m_convertedKeymapPath; - if ( !convertedKeymapPath.isEmpty() ) - { - while ( convertedKeymapPath.startsWith( '/' ) ) + if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) ) { - convertedKeymapPath.remove( 0, 1 ); + return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for the virtual console." ), + tr( "Failed to write to %1" ).arg( vconsoleConfPath ) ); } - convertedKeymapPath = destDir.absoluteFilePath( convertedKeymapPath ); } - if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) ) - return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for the virtual console." ), - tr( "Failed to write to %1" ).arg( vconsoleConfPath ) ); - - if ( !writeX11Data( keyboardConfPath ) ) - return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for X11." ), - tr( "Failed to write to %1" ).arg( keyboardConfPath ) ); - - if ( !defaultKeyboardPath.isEmpty() && m_writeEtcDefaultKeyboard ) { - if ( !writeDefaultKeyboardData( defaultKeyboardPath ) ) - return Calamares::JobResult::error( - tr( "Failed to write keyboard configuration to existing /etc/default directory." ), - tr( "Failed to write to %1" ).arg( keyboardConfPath ) ); + // Get the path to the destination's /etc/X11/xorg.conf.d/00-keyboard.conf + QString xorgConfDPath; + QString keyboardConfPath; + if ( QDir::isAbsolutePath( m_xOrgConfFileName ) ) + { + keyboardConfPath = m_xOrgConfFileName; + while ( keyboardConfPath.startsWith( '/' ) ) + { + keyboardConfPath.remove( 0, 1 ); + } + keyboardConfPath = destDir.absoluteFilePath( keyboardConfPath ); + xorgConfDPath = QFileInfo( keyboardConfPath ).path(); + } + else + { + xorgConfDPath = destDir.absoluteFilePath( "etc/X11/xorg.conf.d" ); + keyboardConfPath = QDir( xorgConfDPath ).absoluteFilePath( m_xOrgConfFileName ); + } + destDir.mkpath( xorgConfDPath ); + + if ( !writeX11Data( keyboardConfPath ) ) + { + return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for X11." ), + tr( "Failed to write to %1" ).arg( keyboardConfPath ) ); + } + } + + { + QString defaultKeyboardPath; + if ( QDir( destDir.absoluteFilePath( "etc/default" ) ).exists() ) + { + defaultKeyboardPath = destDir.absoluteFilePath( "etc/default/keyboard" ); + } + + if ( !defaultKeyboardPath.isEmpty() && m_writeEtcDefaultKeyboard ) + { + if ( !writeDefaultKeyboardData( defaultKeyboardPath ) ) + { + return Calamares::JobResult::error( + tr( "Failed to write keyboard configuration to existing /etc/default directory." ), + tr( "Failed to write to %1" ).arg( defaultKeyboardPath ) ); + } + } } return Calamares::JobResult::ok(); diff --git a/src/modules/keyboard/SetKeyboardLayoutJob.h b/src/modules/keyboard/SetKeyboardLayoutJob.h index f1eabe195..15fadfb52 100644 --- a/src/modules/keyboard/SetKeyboardLayoutJob.h +++ b/src/modules/keyboard/SetKeyboardLayoutJob.h @@ -11,6 +11,7 @@ #ifndef SETKEYBOARDLAYOUTJOB_H #define SETKEYBOARDLAYOUTJOB_H +#include "AdditionalLayoutInfo.h" #include "Job.h" @@ -21,6 +22,7 @@ public: SetKeyboardLayoutJob( const QString& model, const QString& layout, const QString& variant, + const AdditionalLayoutInfo& additionaLayoutInfo, const QString& xOrgConfFileName, const QString& convertedKeymapPath, bool writeEtcDefaultKeyboard ); @@ -38,6 +40,7 @@ private: QString m_model; QString m_layout; QString m_variant; + AdditionalLayoutInfo m_additionalLayoutInfo; QString m_xOrgConfFileName; QString m_convertedKeymapPath; const bool m_writeEtcDefaultKeyboard; diff --git a/src/modules/keyboard/keyboard.qrc b/src/modules/keyboard/keyboard.qrc index dd211e630..4283d8190 100644 --- a/src/modules/keyboard/keyboard.qrc +++ b/src/modules/keyboard/keyboard.qrc @@ -2,5 +2,6 @@ kbd-model-map images/restore.png + non-ascii-layouts diff --git a/src/modules/keyboard/keyboardwidget/keyboardglobal.cpp b/src/modules/keyboard/keyboardwidget/keyboardglobal.cpp index 329913d79..d01c8b591 100644 --- a/src/modules/keyboard/keyboardwidget/keyboardglobal.cpp +++ b/src/modules/keyboard/keyboardwidget/keyboardglobal.cpp @@ -75,7 +75,7 @@ parseKeyboardModels( const char* filepath ) break; } - // here we are in the model section, otherwhise we would continue or break + // here we are in the model section, otherwise we would continue or break QRegExp rx; rx.setPattern( "^\\s+(\\S+)\\s+(\\w.*)\n$" ); @@ -84,12 +84,6 @@ parseKeyboardModels( const char* filepath ) { QString modelDesc = rx.cap( 2 ); QString model = rx.cap( 1 ); - - if ( model == "pc105" ) - { - modelDesc += " - " + QObject::tr( "Default Keyboard Model" ); - } - models.insert( modelDesc, model ); } } diff --git a/src/modules/keyboard/layout-extractor.py b/src/modules/keyboard/layout-extractor.py new file mode 100644 index 000000000..44b0d6b50 --- /dev/null +++ b/src/modules/keyboard/layout-extractor.py @@ -0,0 +1,96 @@ +#! /usr/bin/env python3 +# +# === This file is part of Calamares - === +# +# SPDX-FileCopyrightText: 2020 Adriaan de Groot +# SPDX-License-Identifier: BSD-2-Clause +# +""" +Python3 script to scrape x keyboard layout file and produce translations. + +To use this script, you must have a base.lst in a standard location, +/usr/local/share/X11/xkb/rules/base.lst (this is usual on FreeBSD). + +Prints out a few tables of keyboard model, layout, variant names for +use in translations. +""" + +def scrape_file(file, modelsset, layoutsset, variantsset): + import re + # These RE's match what is in keyboardglobal.cpp + model_re = re.compile("^\\s+(\\S+)\\s+(\\w.*)\n$") + layout_re = re.compile("^\\s+(\\S+)\\s+(\\w.*)\n$") + variant_re = re.compile("^\\s+(\\S+)\\s+(\\S+): (\\w.*)\n$") + + MODEL, LAYOUT, VARIANT = range(3) + state = None + for line in file.readlines(): + # Handle changes in section + if line.startswith("! model"): + state = MODEL + continue + elif line.startswith("! layout"): + state = LAYOUT + continue + elif line.startswith("! variant"): + state = VARIANT + continue + elif not line.strip(): + state = None + # Unchanged from last blank + if state is None: + continue + + if state == MODEL: + m = model_re.match(line) + name = m.groups()[1] + modelsset.add(name) + if state == LAYOUT: + l = layout_re.match(line) + name = l.groups()[1] + layoutsset.add(name) + if state == VARIANT: + v = variant_re.match(line) + name = v.groups()[2] + variantsset.add(name) + + +def write_set(file, label, set): + file.write("/* This returns a reference to local, which is a terrible idea.\n * Good thing it's not meant to be compiled.\n */\n") + # Note {{ is an escaped { for Python string formatting + file.write("class {!s} : public QObject {{\nQ_OBJECT\npublic:\n".format(label)) + file.write("\tconst QStringList& table()\n\t{\n\treturn QStringList {\n") + for x in sorted(set): + file.write("""\t\ttr("{!s}", "{!s}"),\n""".format(x, label)) + file.write("\t\tQString()\n\t};\n}\n}\n\n") + +cpp_header_comment = """/* GENERATED FILE DO NOT EDIT +* +* === This file is part of Calamares - === +* +* SPDX-FileCopyrightText: no +* SPDX-License-Identifier: CC0-1.0 +* +* This file is derived from base.lst in the Xorg distribution +* +*/ + +/** THIS FILE EXISTS ONLY FOR TRANSLATIONS PURPOSES **/ + +// *INDENT-OFF* +// clang-format off +""" + +if __name__ == "__main__": + models=set() + layouts=set() + variants=set() + variants.add( "Default" ) + with open("/usr/local/share/X11/xkb/rules/base.lst", "r") as f: + scrape_file(f, models, layouts, variants) + with open("KeyboardData_p.cxxtr", "w") as f: + f.write(cpp_header_comment) + write_set(f, "kb_models", models) + write_set(f, "kb_layouts", layouts) + write_set(f, "kb_variants", variants) + diff --git a/src/modules/keyboard/non-ascii-layouts b/src/modules/keyboard/non-ascii-layouts new file mode 100644 index 000000000..454278a3e --- /dev/null +++ b/src/modules/keyboard/non-ascii-layouts @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# +# Layouts stored here need additional layout (usually us) to provide ASCII support for user + +#layout additional-layout additional-variant vconsole-keymap +ru us - ruwin_alt_sh-UTF-8 +ua us - ua-utf diff --git a/src/modules/keyboardq/KeyboardQmlViewStep.cpp b/src/modules/keyboardq/KeyboardQmlViewStep.cpp index d42ab5269..e8ae630e7 100644 --- a/src/modules/keyboardq/KeyboardQmlViewStep.cpp +++ b/src/modules/keyboardq/KeyboardQmlViewStep.cpp @@ -2,6 +2,7 @@ * * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac * SPDX-FileCopyrightText: 2020 Camilo Higuita + * SPDX-FileCopyrightText: 2020 Anke Boersma * SPDX-License-Identifier: GPL-3.0-or-later * * Calamares is Free Software: see the License-Identifier above. @@ -10,21 +11,19 @@ #include "KeyboardQmlViewStep.h" +#include "Config.h" + #include "GlobalStorage.h" #include "JobQueue.h" -#include "utils/Variant.h" CALAMARES_PLUGIN_FACTORY_DEFINITION( KeyboardQmlViewStepFactory, registerPlugin< KeyboardQmlViewStep >(); ) KeyboardQmlViewStep::KeyboardQmlViewStep( QObject* parent ) : Calamares::QmlViewStep( parent ) , m_config( new Config( this ) ) - , m_nextEnabled( false ) - , m_writeEtcDefaultKeyboard( true ) { - m_config->init(); - m_nextEnabled = true; - emit nextStatusChanged( m_nextEnabled ); + m_config->detectCurrentKeyboardLayout(); + emit nextStatusChanged( true ); } QString @@ -36,13 +35,13 @@ KeyboardQmlViewStep::prettyName() const QString KeyboardQmlViewStep::prettyStatus() const { - return m_prettyStatus; + return m_config->prettyStatus(); } bool KeyboardQmlViewStep::isNextEnabled() const { - return m_nextEnabled; + return true; } bool @@ -66,7 +65,7 @@ KeyboardQmlViewStep::isAtEnd() const Calamares::JobList KeyboardQmlViewStep::jobs() const { - return m_jobs; + return m_config->createJobs(); } void @@ -79,8 +78,6 @@ void KeyboardQmlViewStep::onLeave() { m_config->finalize(); - m_jobs = m_config->createJobs( m_xOrgConfFileName, m_convertedKeymapPath, m_writeEtcDefaultKeyboard ); - m_prettyStatus = m_config->prettyStatus(); } QObject* @@ -92,39 +89,6 @@ KeyboardQmlViewStep::getConfig() void KeyboardQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { - using namespace CalamaresUtils; - - if ( configurationMap.contains( "xOrgConfFileName" ) - && configurationMap.value( "xOrgConfFileName" ).type() == QVariant::String - && !getString( configurationMap, "xOrgConfFileName" ).isEmpty() ) - { - m_xOrgConfFileName = getString( configurationMap, "xOrgConfFileName" ); - } - else - { - m_xOrgConfFileName = "00-keyboard.conf"; - } - - if ( configurationMap.contains( "convertedKeymapPath" ) - && configurationMap.value( "convertedKeymapPath" ).type() == QVariant::String - && !getString( configurationMap, "convertedKeymapPath" ).isEmpty() ) - { - m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" ); - } - else - { - m_convertedKeymapPath = QString(); - } - - if ( configurationMap.contains( "writeEtcDefaultKeyboard" ) - && configurationMap.value( "writeEtcDefaultKeyboard" ).type() == QVariant::Bool ) - { - m_writeEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true ); - } - else - { - m_writeEtcDefaultKeyboard = true; - } - + m_config->setConfigurationMap( configurationMap ); Calamares::QmlViewStep::setConfigurationMap( configurationMap ); } diff --git a/src/modules/keyboardq/KeyboardQmlViewStep.h b/src/modules/keyboardq/KeyboardQmlViewStep.h index 4571a9a60..eb31c3d59 100644 --- a/src/modules/keyboardq/KeyboardQmlViewStep.h +++ b/src/modules/keyboardq/KeyboardQmlViewStep.h @@ -13,14 +13,12 @@ #include "Config.h" -#include -#include -#include +#include "DllMacro.h" +#include "utils/PluginFactory.h" +#include "viewpages/QmlViewStep.h" #include -class KeyboardPage; - class PLUGINDLLEXPORT KeyboardQmlViewStep : public Calamares::QmlViewStep { Q_OBJECT @@ -47,14 +45,6 @@ public: private: Config* m_config; - bool m_nextEnabled; - QString m_prettyStatus; - - QString m_xOrgConfFileName; - QString m_convertedKeymapPath; - bool m_writeEtcDefaultKeyboard; - - Calamares::JobList m_jobs; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( KeyboardQmlViewStepFactory ) diff --git a/src/modules/keyboardq/keyboardq.qrc b/src/modules/keyboardq/keyboardq.qrc index 492f6e213..d2473a8ec 100644 --- a/src/modules/keyboardq/keyboardq.qrc +++ b/src/modules/keyboardq/keyboardq.qrc @@ -3,5 +3,6 @@ ../keyboard/kbd-model-map ../keyboard/images/restore.png keyboardq.qml + ../keyboard/non-ascii-layouts diff --git a/src/modules/license/LicenseWidget.cpp b/src/modules/license/LicenseWidget.cpp index b2e66515d..a8d581ab5 100644 --- a/src/modules/license/LicenseWidget.cpp +++ b/src/modules/license/LicenseWidget.cpp @@ -13,6 +13,7 @@ #include "LicenseWidget.h" #include "utils/Logger.h" +#include "utils/QtCompat.h" #include #include @@ -48,7 +49,7 @@ LicenseWidget::LicenseWidget( LicenseEntry entry, QWidget* parent ) , m_isExpanded( m_entry.expandByDefault() ) { QPalette pal( palette() ); - pal.setColor( QPalette::Background, palette().window().color().lighter( 108 ) ); + pal.setColor( WindowBackground, palette().window().color().lighter( 108 ) ); setObjectName( "licenseItem" ); diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp index 7a6ed8b15..e296b790b 100644 --- a/src/modules/locale/LocalePage.cpp +++ b/src/modules/locale/LocalePage.cpp @@ -91,10 +91,16 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) // Set up the location before connecting signals, to avoid a signal // storm as various parts interact. - m_regionCombo->setModel( m_config->regionModel() ); - m_zoneCombo->setModel( m_config->regionalZonesModel() ); - locationChanged( m_config->currentLocation() ); // doesn't inform TZ widget - m_tzWidget->setCurrentLocation( m_config->currentLocation() ); + { + auto* regions = m_config->regionModel(); + auto* zones = m_config->regionalZonesModel(); + auto* location = m_config->currentLocation(); + zones->setRegion( location->region() ); + m_regionCombo->setModel( regions ); + m_zoneCombo->setModel( zones ); + m_tzWidget->setCurrentLocation( location ); + locationChanged( location ); // doesn't inform TZ widget + } connect( config, &Config::currentLCStatusChanged, m_formatsLabel, &QLabel::setText ); connect( config, &Config::currentLanguageStatusChanged, m_localeLabel, &QLabel::setText ); diff --git a/src/modules/locale/timezonewidget/TimeZoneImage.cpp b/src/modules/locale/timezonewidget/TimeZoneImage.cpp index 54aa1afd5..ad772ef63 100644 --- a/src/modules/locale/timezonewidget/TimeZoneImage.cpp +++ b/src/modules/locale/timezonewidget/TimeZoneImage.cpp @@ -24,9 +24,6 @@ static_assert( TimeZoneImageList::zoneCount == ( sizeof( zoneNames ) / sizeof( z #define ZONE_NAME QStringLiteral( "zone" ) -/* static constexpr */ const int TimeZoneImageList::zoneCount; -/* static constexpr */ const QSize TimeZoneImageList::imageSize; - static_assert( TimeZoneImageList::zoneCount == 37, "Incorrect number of zones" ); TimeZoneImageList::TimeZoneImageList() {} diff --git a/src/modules/machineid/MachineIdJob.cpp b/src/modules/machineid/MachineIdJob.cpp index 8a33288b9..fef63828a 100644 --- a/src/modules/machineid/MachineIdJob.cpp +++ b/src/modules/machineid/MachineIdJob.cpp @@ -153,18 +153,13 @@ MachineIdJob::setConfigurationMap( const QVariantMap& map ) m_dbus_symlink = m_dbus && m_dbus_symlink; m_entropy_copy = CalamaresUtils::getBool( map, "entropy-copy", false ); - m_entropy_files = CalamaresUtils::getStringList( map, "entropy-files" ); if ( CalamaresUtils::getBool( map, "entropy", false ) ) { - cWarning() << "MachineId:: configuration setting *entropy* is deprecated, use *entropy-files*."; - - QString target_entropy_file = QStringLiteral( "/var/lib/urandom/random-seed" ); - if ( !m_entropy_files.contains( target_entropy_file ) ) - { - m_entropy_files.append( target_entropy_file ); - } + cWarning() << "MachineId:: configuration setting *entropy* is deprecated, use *entropy-files* instead."; + m_entropy_files.append( QStringLiteral( "/var/lib/urandom/random-seed" ) ); } + m_entropy_files.removeDuplicates(); } CALAMARES_PLUGIN_FACTORY_DEFINITION( MachineIdJobFactory, registerPlugin< MachineIdJob >(); ) diff --git a/src/modules/machineid/machineid.conf b/src/modules/machineid/machineid.conf index c6189e598..15e190299 100644 --- a/src/modules/machineid/machineid.conf +++ b/src/modules/machineid/machineid.conf @@ -11,21 +11,39 @@ # --- # Whether to create /etc/machine-id for systemd. +# The default is *false*. systemd: true # Whether to create /var/lib/dbus/machine-id for D-Bus. +# The default is *false*. dbus: true # Whether /var/lib/dbus/machine-id should be a symlink to /etc/machine-id # (ignored if dbus is false, or if there is no /etc/machine-id to point to). +# The default is *false*. dbus-symlink: true -# Whether to create an entropy file /var/lib/urandom/random-seed -# -# DEPRECATED: list the file in entropy-files instead -entropy: false -# Whether to copy entropy from the host +# Copy entropy from the host? If this is set to *true*, then +# any entropy file listed below will be copied from the host +# if it exists. Non-existent files will be generated from +# /dev/urandom . The default is *false*. entropy-copy: false -# Which files to write (paths in the target) +# Which files to write (paths in the target). Each of these files is +# either generated from /dev/urandom or copied from the host, depending +# on the setting for *entropy-copy*, above. entropy-files: - /var/lib/urandom/random-seed - /var/lib/systemd/random-seed + +# Whether to create an entropy file /var/lib/urandom/random-seed +# +# DEPRECATED: list the file in entropy-files instead. If this key +# exists and is set to *true*, a warning is printed and Calamares +# behaves as if `/var/lib/urandom/random-seed` is listed in *entropy-files*. +# +# entropy: false + +# Whether to create a symlink for D-Bus +# +# DEPRECATED: set *dbus-symlink* with the same meaning instead. +# +# symlink: false diff --git a/src/modules/machineid/machineid.schema.yaml b/src/modules/machineid/machineid.schema.yaml index 1ae67e132..59bb5f81b 100644 --- a/src/modules/machineid/machineid.schema.yaml +++ b/src/modules/machineid/machineid.schema.yaml @@ -6,11 +6,11 @@ $id: https://calamares.io/schemas/machineid additionalProperties: false type: object properties: - systemd: { type: boolean, default: true } - dbus: { type: boolean, default: true } - "dbus-symlink": { type: boolean, default: true } + systemd: { type: boolean, default: false } + dbus: { type: boolean, default: false } + "dbus-symlink": { type: boolean, default: false } "entropy-copy": { type: boolean, default: false } "entropy-files": { type: array, items: { type: string } } # Deprecated properties - symlink: { type: boolean, default: true } + symlink: { type: boolean, default: false } entropy: { type: boolean, default: false } diff --git a/src/modules/mount/main.py b/src/modules/mount/main.py index 01c0650bf..1313fca49 100644 --- a/src/modules/mount/main.py +++ b/src/modules/mount/main.py @@ -7,6 +7,7 @@ # SPDX-FileCopyrightText: 2017 Alf Gaida # SPDX-FileCopyrightText: 2019 Adriaan de Groot # SPDX-FileCopyrightText: 2019 Kevin Kofler +# SPDX-FileCopyrightText: 2019-2020 Collabora Ltd # SPDX-License-Identifier: GPL-3.0-or-later # # Calamares is Free Software: see the License-Identifier above. @@ -38,6 +39,9 @@ def mount_partition(root_mount_point, partition, partitions): # Create mount point with `+` rather than `os.path.join()` because # `partition["mountPoint"]` starts with a '/'. raw_mount_point = partition["mountPoint"] + if not raw_mount_point: + return + mount_point = root_mount_point + raw_mount_point # Ensure that the created directory has the correct SELinux context on @@ -52,26 +56,22 @@ def mount_partition(root_mount_point, partition, partitions): raise fstype = partition.get("fs", "").lower() + if fstype == "unformatted": + return if fstype == "fat16" or fstype == "fat32": fstype = "vfat" - if "luksMapperName" in partition: - libcalamares.utils.debug( - "about to mount {!s}".format(partition["luksMapperName"])) - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - mount_point, - fstype, - partition.get("options", ""), - ) + device = partition["device"] - else: - libcalamares.utils.mount(partition["device"], - mount_point, - fstype, - partition.get("options", ""), - ) + if "luksMapperName" in partition: + device = os.path.join("/dev/mapper", partition["luksMapperName"]) + + if libcalamares.utils.mount(device, + mount_point, + fstype, + partition.get("options", "")) != 0: + libcalamares.utils.warning("Cannot mount {}".format(device)) # If the root partition is btrfs, we create a subvolume "@" # for the root mount point. @@ -96,37 +96,23 @@ def mount_partition(root_mount_point, partition, partitions): subprocess.check_call(["umount", "-v", root_mount_point]) + device = partition["device"] + if "luksMapperName" in partition: - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - mount_point, - fstype, - ",".join( - ["subvol=@", partition.get("options", "")]), - ) - if not has_home_mount_point: - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - root_mount_point + "/home", - fstype, - ",".join( - ["subvol=@home", partition.get("options", "")]), - ) - else: - libcalamares.utils.mount( - partition["device"], - mount_point, - fstype, - ",".join(["subvol=@", partition.get("options", "")]), - ) - if not has_home_mount_point: - libcalamares.utils.mount( - partition["device"], - root_mount_point + "/home", - fstype, - ",".join( - ["subvol=@home", partition.get("options", "")]), - ) + device = os.path.join("/dev/mapper", partition["luksMapperName"]) + + if libcalamares.utils.mount(device, + mount_point, + fstype, + ",".join(["subvol=@", partition.get("options", "")])) != 0: + libcalamares.utils.warning("Cannot mount {}".format(device)) + + if not has_home_mount_point: + if libcalamares.utils.mount(device, + root_mount_point + "/home", + fstype, + ",".join(["subvol=@home", partition.get("options", "")])) != 0: + libcalamares.utils.warning("Cannot mount {}".format(device)) def run(): diff --git a/src/modules/mount/mount.conf b/src/modules/mount/mount.conf index 1e70465c2..3a117d32c 100644 --- a/src/modules/mount/mount.conf +++ b/src/modules/mount/mount.conf @@ -12,10 +12,13 @@ # Extra filesystems to mount. The key's value is a list of entries; each # entry has four keys: # - device The device node to mount -# - fs The filesystem type to use +# - fs (optional) The filesystem type to use # - mountPoint Where to mount the filesystem # - options (optional) Extra options to pass to mount(8) # +# The device is not mounted if the mountPoint is unset or if the fs is +# set to unformatted. +# extraMounts: - device: proc fs: proc diff --git a/src/modules/netinstall/Config.cpp b/src/modules/netinstall/Config.cpp index ddbb36fcc..e69b3c2a4 100644 --- a/src/modules/netinstall/Config.cpp +++ b/src/modules/netinstall/Config.cpp @@ -43,7 +43,7 @@ Config::status() const case Status::FailedNetworkError: return tr( "Network Installation. (Disabled: Unable to fetch package lists, check your network connection)" ); } - NOTREACHED return QString(); + __builtin_unreachable(); } diff --git a/src/modules/netinstall/NetInstallViewStep.cpp b/src/modules/netinstall/NetInstallViewStep.cpp index beb295c32..e96d1724f 100644 --- a/src/modules/netinstall/NetInstallViewStep.cpp +++ b/src/modules/netinstall/NetInstallViewStep.cpp @@ -47,7 +47,7 @@ NetInstallViewStep::prettyName() const return m_sidebarLabel ? m_sidebarLabel->get() : tr( "Package selection" ); #if defined( TABLE_OF_TRANSLATIONS ) - NOTREACHED + __builtin_unreachable(); // This is a table of "standard" labels for this module. If you use them // in the label: sidebar: section of the config file, the existing // translations can be used. diff --git a/src/modules/netinstall/PackageModel.cpp b/src/modules/netinstall/PackageModel.cpp index 147bd5a5c..d4887b6c2 100644 --- a/src/modules/netinstall/PackageModel.cpp +++ b/src/modules/netinstall/PackageModel.cpp @@ -267,8 +267,13 @@ PackageModel::setupModelData( const QVariantList& groupList, PackageTreeItem* pa setupModelData( subgroups, item ); // The children might be checked while the parent isn't (yet). // Children are added to their parent (below) without affecting - // the checked-state -- do it manually. - item->updateSelected(); + // the checked-state -- do it manually. Items with subgroups + // but no children have only hidden children -- those get + // handled specially. + if ( item->childCount() > 0 ) + { + item->updateSelected(); + } } else { diff --git a/src/modules/packagechooser/PackageChooserPage.cpp b/src/modules/packagechooser/PackageChooserPage.cpp index 0d5df8177..e46809fdd 100644 --- a/src/modules/packagechooser/PackageChooserPage.cpp +++ b/src/modules/packagechooser/PackageChooserPage.cpp @@ -33,12 +33,12 @@ PackageChooserPage::PackageChooserPage( PackageChooserMode mode, QWidget* parent switch ( mode ) { case PackageChooserMode::Optional: - FALLTHRU; + [[fallthrough]]; case PackageChooserMode::Required: ui->products->setSelectionMode( QAbstractItemView::SingleSelection ); break; case PackageChooserMode::OptionalMultiple: - FALLTHRU; + [[fallthrough]]; case PackageChooserMode::RequiredMultiple: ui->products->setSelectionMode( QAbstractItemView::ExtendedSelection ); } diff --git a/src/modules/packagechooser/PackageChooserViewStep.cpp b/src/modules/packagechooser/PackageChooserViewStep.cpp index f162c074b..d576f2753 100644 --- a/src/modules/packagechooser/PackageChooserViewStep.cpp +++ b/src/modules/packagechooser/PackageChooserViewStep.cpp @@ -110,8 +110,7 @@ PackageChooserViewStep::isNextEnabled() const // exactly one OR one or more return m_widget->hasSelection(); } - - NOTREACHED return true; + __builtin_unreachable(); } diff --git a/src/modules/partition/core/Config.cpp b/src/modules/partition/core/Config.cpp index 55e0d8d0a..0afcee83d 100644 --- a/src/modules/partition/core/Config.cpp +++ b/src/modules/partition/core/Config.cpp @@ -190,7 +190,7 @@ Config::setSwapChoice( int c ) { if ( ( c < SwapChoice::NoSwap ) || ( c > SwapChoice::SwapFile ) ) { - cWarning() << "Instalid swap choice (int)" << c; + cWarning() << "Invalid swap choice (int)" << c; c = SwapChoice::NoSwap; } setSwapChoice( static_cast< SwapChoice >( c ) ); diff --git a/src/modules/partition/core/Config.h b/src/modules/partition/core/Config.h index 1629ccc22..57230b6e8 100644 --- a/src/modules/partition/core/Config.h +++ b/src/modules/partition/core/Config.h @@ -28,7 +28,7 @@ class Config : public QObject public: Config( QObject* parent ); - virtual ~Config() = default; + ~Config() override = default; enum InstallChoice { diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp index e6c1a520d..92bcbace0 100644 --- a/src/modules/partition/core/PartUtils.cpp +++ b/src/modules/partition/core/PartUtils.cpp @@ -1,7 +1,7 @@ /* === This file is part of Calamares - === * * SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac - * Copyright 2018-2019 Adriaan de Groot + * SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot * SPDX-FileCopyrightText: 2019 Collabora Ltd * SPDX-License-Identifier: GPL-3.0-or-later * @@ -59,7 +59,7 @@ convenienceName( const Partition* const candidate ) QString p; QTextStream s( &p ); - s << (void*)candidate; + s << static_cast< const void* >( candidate ); // No good name available, use pointer address return p; } @@ -439,11 +439,14 @@ isEfiSystem() bool isEfiBootable( const Partition* candidate ) { - cDebug() << "Check EFI bootable" << convenienceName( candidate ) << candidate->devicePath(); - cDebug() << Logger::SubEntry << "flags" << candidate->activeFlags(); - - auto flags = PartitionInfo::flags( candidate ); + const auto flags = PartitionInfo::flags( candidate ); + // TODO: with KPMCore 4, this comment is wrong: the flags + // are remapped, and the ESP flag is the same as Boot. +#if defined( WITH_KPMCORE4API ) + static_assert( KPM_PARTITION_FLAG_ESP == KPM_PARTITION_FLAG( Boot ), "KPMCore API enum changed" ); + return flags.testFlag( KPM_PARTITION_FLAG_ESP ); +#else /* If bit 17 is set, old-style Esp flag, it's OK */ if ( flags.testFlag( KPM_PARTITION_FLAG_ESP ) ) { @@ -455,19 +458,28 @@ isEfiBootable( const Partition* candidate ) while ( root && !root->isRoot() ) { root = root->parent(); - cDebug() << Logger::SubEntry << "moved towards root" << Logger::Pointer( root ); } // Strange case: no root found, no partition table node? if ( !root ) { + cWarning() << "No root of partition table found."; return false; } const PartitionTable* table = dynamic_cast< const PartitionTable* >( root ); - cDebug() << Logger::SubEntry << "partition table" << Logger::Pointer( table ) << "type" - << ( table ? table->type() : PartitionTable::TableType::unknownTableType ); - return table && ( table->type() == PartitionTable::TableType::gpt ) && flags.testFlag( KPM_PARTITION_FLAG( Boot ) ); + if ( !table ) + { + cWarning() << "Root of partition table is not a PartitionTable object"; + return false; + } + if ( table->type() == PartitionTable::TableType::gpt ) + { + const auto bootFlag = KPM_PARTITION_FLAG( Boot ); + return flags.testFlag( bootFlag ); + } + return false; +#endif } QString diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index a78e8ff53..dc3b0b572 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -97,21 +97,6 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO // empty and a EFI boot partition, while BIOS starts at // the 1MiB boundary (usually sector 2048). int empty_space_sizeB = isEfi ? 2_MiB : 1_MiB; - int uefisys_part_sizeB = 0_MiB; - - if ( isEfi ) - { - if ( gs->contains( "efiSystemPartitionSize" ) ) - { - CalamaresUtils::Partition::PartitionSize part_size - = CalamaresUtils::Partition::PartitionSize( gs->value( "efiSystemPartitionSize" ).toString() ); - uefisys_part_sizeB = part_size.toBytes( dev->capacity() ); - } - else - { - uefisys_part_sizeB = 300_MiB; - } - } // Since sectors count from 0, if the space is 2048 sectors in size, // the first free sector has number 2048 (and there are 2048 sectors @@ -128,6 +113,14 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO if ( isEfi ) { + int uefisys_part_sizeB = 300_MiB; + if ( gs->contains( "efiSystemPartitionSize" ) ) + { + CalamaresUtils::Partition::PartitionSize part_size + = CalamaresUtils::Partition::PartitionSize( gs->value( "efiSystemPartitionSize" ).toString() ); + uefisys_part_sizeB = part_size.toBytes( dev->capacity() ); + } + qint64 efiSectorCount = CalamaresUtils::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() ); Q_ASSERT( efiSectorCount > 0 ); @@ -203,6 +196,10 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO KPM_PARTITION_FLAG( None ) ); } PartitionInfo::setFormat( swapPartition, true ); + if ( gs->contains( "swapPartitionName" ) ) + { + swapPartition->setLabel( gs->value( "swapPartitionName" ).toString() ); + } core->createPartition( dev, swapPartition ); } diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 3d726aef1..254d007c1 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -110,7 +110,7 @@ updatePreview( Job* job, const std::true_type& ) template < typename Job > void -updatePreview( Job* job, const std::false_type& ) +updatePreview( Job*, const std::false_type& ) { } @@ -483,7 +483,6 @@ PartitionCoreModule::deletePartition( Device* device, Partition* partition ) } } - const Calamares::JobList& jobs = deviceInfo->jobs(); if ( partition->state() == KPM_PARTITION_STATE( New ) ) { // Take all the SetPartFlagsJob from the list and delete them @@ -717,6 +716,8 @@ PartitionCoreModule::updateIsDirty() void PartitionCoreModule::scanForEfiSystemPartitions() { + const bool wasEmpty = m_efiSystemPartitions.isEmpty(); + m_efiSystemPartitions.clear(); QList< Device* > devices; @@ -733,6 +734,11 @@ PartitionCoreModule::scanForEfiSystemPartitions() { cWarning() << "system is EFI but no EFI system partitions found."; } + else if ( wasEmpty ) + { + // But it isn't empty anymore, so whatever problem has been solved + cDebug() << "system is EFI and new EFI system partition has been found."; + } m_efiSystemPartitions = efiSystemPartitions; } @@ -862,81 +868,9 @@ PartitionCoreModule::setBootLoaderInstallPath( const QString& path ) } void -PartitionCoreModule::initLayout() +PartitionCoreModule::initLayout( FileSystem::Type defaultFsType, const QVariantList& config ) { - m_partLayout = new PartitionLayout(); - - m_partLayout->addEntry( QString( "/" ), QString( "100%" ) ); -} - -void -PartitionCoreModule::initLayout( const QVariantList& config ) -{ - bool ok; - QString sizeString; - QString minSizeString; - QString maxSizeString; - - m_partLayout = new PartitionLayout(); - - for ( const auto& r : config ) - { - QVariantMap pentry = r.toMap(); - - if ( !pentry.contains( "name" ) || !pentry.contains( "mountPoint" ) || !pentry.contains( "filesystem" ) - || !pentry.contains( "size" ) ) - { - cError() << "Partition layout entry #" << config.indexOf( r ) - << "lacks mandatory attributes, switching to default layout."; - delete ( m_partLayout ); - initLayout(); - break; - } - - if ( pentry.contains( "size" ) && CalamaresUtils::getString( pentry, "size" ).isEmpty() ) - { - sizeString.setNum( CalamaresUtils::getInteger( pentry, "size", 0 ) ); - } - else - { - sizeString = CalamaresUtils::getString( pentry, "size" ); - } - - if ( pentry.contains( "minSize" ) && CalamaresUtils::getString( pentry, "minSize" ).isEmpty() ) - { - minSizeString.setNum( CalamaresUtils::getInteger( pentry, "minSize", 0 ) ); - } - else - { - minSizeString = CalamaresUtils::getString( pentry, "minSize" ); - } - - if ( pentry.contains( "maxSize" ) && CalamaresUtils::getString( pentry, "maxSize" ).isEmpty() ) - { - maxSizeString.setNum( CalamaresUtils::getInteger( pentry, "maxSize", 0 ) ); - } - else - { - maxSizeString = CalamaresUtils::getString( pentry, "maxSize" ); - } - - if ( !m_partLayout->addEntry( CalamaresUtils::getString( pentry, "name" ), - CalamaresUtils::getString( pentry, "uuid" ), - CalamaresUtils::getString( pentry, "type" ), - CalamaresUtils::getUnsignedInteger( pentry, "attributes", 0 ), - CalamaresUtils::getString( pentry, "mountPoint" ), - CalamaresUtils::getString( pentry, "filesystem" ), - CalamaresUtils::getSubMap( pentry, "features", ok ), - sizeString, - minSizeString, - maxSizeString ) ) - { - cError() << "Partition layout entry #" << config.indexOf( r ) << "is invalid, switching to default layout."; - delete ( m_partLayout ); - initLayout(); - break; - } - } + m_partLayout.init( defaultFsType, config ); } void @@ -948,7 +882,8 @@ PartitionCoreModule::layoutApply( Device* dev, const PartitionRole& role ) { bool isEfi = PartUtils::isEfiSystem(); - QList< Partition* > partList = m_partLayout->execute( dev, firstSector, lastSector, luksPassphrase, parent, role ); + QList< Partition* > partList + = m_partLayout.createPartitions( dev, firstSector, lastSector, luksPassphrase, parent, role ); // Partition::mountPoint() tells us where it is mounted **now**, while // PartitionInfo::mountPoint() says where it will be mounted in the target system. diff --git a/src/modules/partition/core/PartitionCoreModule.h b/src/modules/partition/core/PartitionCoreModule.h index 1dc61db6f..46604b97c 100644 --- a/src/modules/partition/core/PartitionCoreModule.h +++ b/src/modules/partition/core/PartitionCoreModule.h @@ -85,7 +85,7 @@ public: }; PartitionCoreModule( QObject* parent = nullptr ); - ~PartitionCoreModule(); + ~PartitionCoreModule() override; /** * @brief init performs a devices scan and initializes all KPMcore data @@ -156,8 +156,11 @@ public: /// @brief Set the path where the bootloader will be installed void setBootLoaderInstallPath( const QString& path ); - void initLayout(); - void initLayout( const QVariantList& config ); + /** @brief Initialize the default layout that will be applied + * + * See PartitionLayout::init() + */ + void initLayout( FileSystem::Type defaultFsType, const QVariantList& config = QVariantList() ); void layoutApply( Device* dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase ); void layoutApply( Device* dev, @@ -256,7 +259,7 @@ private: bool m_hasRootMountPoint = false; bool m_isDirty = false; QString m_bootLoaderInstallPath; - PartitionLayout* m_partLayout; + PartitionLayout m_partLayout; OsproberEntryList m_osproberLines; diff --git a/src/modules/partition/core/PartitionInfo.cpp b/src/modules/partition/core/PartitionInfo.cpp index 87aa03b66..c4d239db8 100644 --- a/src/modules/partition/core/PartitionInfo.cpp +++ b/src/modules/partition/core/PartitionInfo.cpp @@ -52,7 +52,15 @@ PartitionTable::Flags flags( const Partition* partition ) { auto v = partition->property( FLAGS_PROPERTY ); - if ( v.type() == QVariant::Int ) + if ( !v.isValid() ) + { + return partition->activeFlags(); + } + // The underlying type of PartitionTable::Flags can be int or uint + // (see qflags.h) and so setting those flags can create a QVariant + // of those types; we don't just want to check QVariant::canConvert() + // here because that will also accept QByteArray and some other things. + if ( v.type() == QVariant::Int || v.type() == QVariant::UInt ) { return static_cast< PartitionTable::Flags >( v.toInt() ); } diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index 182e7606b..d6f817af7 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -21,313 +21,263 @@ #include "core/PartitionActions.h" #include "core/PartitionInfo.h" +#include "utils/Variant.h" + #include #include #include -static FileSystem::Type -getDefaultFileSystemType() -{ - Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); - FileSystem::Type defaultFS = FileSystem::Ext4; - - if ( gs->contains( "defaultFileSystemType" ) ) - { - PartUtils::findFS( gs->value( "defaultFileSystemType" ).toString(), &defaultFS ); - if ( defaultFS == FileSystem::Unknown ) - { - defaultFS = FileSystem::Ext4; - } - } - - return defaultFS; -} - -PartitionLayout::PartitionLayout() -{ - m_defaultFsType = getDefaultFileSystemType(); -} - -PartitionLayout::PartitionLayout( PartitionLayout::PartitionEntry entry ) -{ - m_defaultFsType = getDefaultFileSystemType(); - m_partLayout.append( entry ); -} +PartitionLayout::PartitionLayout() {} PartitionLayout::PartitionLayout( const PartitionLayout& layout ) - : m_defaultFsType( layout.m_defaultFsType ) - , m_partLayout( layout.m_partLayout ) + : m_partLayout( layout.m_partLayout ) { } PartitionLayout::~PartitionLayout() {} -bool -PartitionLayout::addEntry( PartitionLayout::PartitionEntry entry ) -{ - if ( !entry.isValid() ) - { - cError() << "Partition size is invalid or has min size > max size"; - return false; - } - - m_partLayout.append( entry ); - - return true; -} - PartitionLayout::PartitionEntry::PartitionEntry() : partAttributes( 0 ) { } -PartitionLayout::PartitionEntry::PartitionEntry( const QString& size, const QString& min, const QString& max ) - : partSize( size ) - , partMinSize( min ) - , partMaxSize( max ) - , partAttributes( 0 ) +PartitionLayout::PartitionEntry::PartitionEntry( FileSystem::Type fs, + const QString& mountPoint, + const QString& size, + const QString& minSize, + const QString& maxSize ) + : partAttributes( 0 ) + , partMountPoint( mountPoint ) + , partFileSystem( fs ) + , partSize( size ) + , partMinSize( minSize ) + , partMaxSize( maxSize ) { } -bool -PartitionLayout::addEntry( const QString& mountPoint, const QString& size, const QString& min, const QString& max ) +PartitionLayout::PartitionEntry::PartitionEntry( const QString& label, + const QString& uuid, + const QString& type, + quint64 attributes, + const QString& mountPoint, + const QString& fs, + const QVariantMap& features, + const QString& size, + const QString& minSize, + const QString& maxSize ) + : partLabel( label ) + , partUUID( uuid ) + , partType( type ) + , partAttributes( attributes ) + , partMountPoint( mountPoint ) + , partFeatures( features ) + , partSize( size ) + , partMinSize( minSize ) + , partMaxSize( maxSize ) { - PartitionLayout::PartitionEntry entry( size, min, max ); + PartUtils::findFS( fs, &partFileSystem ); +} + +bool +PartitionLayout::addEntry( const PartitionEntry& entry ) +{ if ( !entry.isValid() ) { - cError() << "Partition size" << size << "is invalid or" << min << ">" << max; return false; } - if ( mountPoint.isEmpty() || !mountPoint.startsWith( QString( "/" ) ) ) - { - cError() << "Partition mount point" << mountPoint << "is invalid"; - return false; - } - - entry.partMountPoint = mountPoint; - entry.partFileSystem = m_defaultFsType; m_partLayout.append( entry ); return true; } -bool -PartitionLayout::addEntry( const QString& label, - const QString& uuid, - const QString& type, - quint64 attributes, - const QString& mountPoint, - const QString& fs, - const QVariantMap& features, - const QString& size, - const QString& min, - const QString& max ) +void +PartitionLayout::init( FileSystem::Type defaultFsType, const QVariantList& config ) { - PartitionLayout::PartitionEntry entry( size, min, max ); + bool ok; - if ( !entry.isValid() ) + m_partLayout.clear(); + + for ( const auto& r : config ) { - cError() << "Partition size" << size << "is invalid or" << min << ">" << max; - return false; - } - if ( mountPoint.isEmpty() || !mountPoint.startsWith( QString( "/" ) ) ) - { - cError() << "Partition mount point" << mountPoint << "is invalid"; - return false; + QVariantMap pentry = r.toMap(); + + if ( !pentry.contains( "name" ) || !pentry.contains( "size" ) ) + { + cError() << "Partition layout entry #" << config.indexOf( r ) + << "lacks mandatory attributes, switching to default layout."; + m_partLayout.clear(); + break; + } + + if ( !addEntry( { CalamaresUtils::getString( pentry, "name" ), + CalamaresUtils::getString( pentry, "uuid" ), + CalamaresUtils::getString( pentry, "type" ), + CalamaresUtils::getUnsignedInteger( pentry, "attributes", 0 ), + CalamaresUtils::getString( pentry, "mountPoint" ), + CalamaresUtils::getString( pentry, "filesystem", "unformatted" ), + CalamaresUtils::getSubMap( pentry, "features", ok ), + CalamaresUtils::getString( pentry, "size", QStringLiteral( "0" ) ), + CalamaresUtils::getString( pentry, "minSize", QStringLiteral( "0" ) ), + CalamaresUtils::getString( pentry, "maxSize", QStringLiteral( "0" ) ) } ) ) + { + cError() << "Partition layout entry #" << config.indexOf( r ) << "is invalid, switching to default layout."; + m_partLayout.clear(); + break; + } } - entry.partLabel = label; - entry.partUUID = uuid; - entry.partType = type; - entry.partAttributes = attributes; - entry.partMountPoint = mountPoint; - PartUtils::findFS( fs, &entry.partFileSystem ); - if ( entry.partFileSystem == FileSystem::Unknown ) + if ( !m_partLayout.count() ) { - entry.partFileSystem = m_defaultFsType; + addEntry( { defaultFsType, QString( "/" ), QString( "100%" ) } ); } - entry.partFeatures = features; - - m_partLayout.append( entry ); - - return true; } QList< Partition* > -PartitionLayout::execute( Device* dev, - qint64 firstSector, - qint64 lastSector, - QString luksPassphrase, - PartitionNode* parent, - const PartitionRole& role ) +PartitionLayout::createPartitions( Device* dev, + qint64 firstSector, + qint64 lastSector, + QString luksPassphrase, + PartitionNode* parent, + const PartitionRole& role ) { QList< Partition* > partList; // Map each partition entry to its requested size (0 when calculated later) - QMap< const PartitionLayout::PartitionEntry*, qint64 > partSizeMap; - qint64 totalSize = lastSector - firstSector + 1; - qint64 availableSize = totalSize; + QMap< const PartitionLayout::PartitionEntry*, qint64 > partSectorsMap; + const qint64 totalSectors = lastSector - firstSector + 1; + qint64 currentSector, availableSectors = totalSectors; - // Let's check if we have enough space for each partSize - for ( const auto& part : qAsConst( m_partLayout ) ) + // Let's check if we have enough space for each partitions, using the size + // propery or the min-size property if unit is in percentage. + for ( const auto& entry : qAsConst( m_partLayout ) ) { - qint64 size; - // Calculate partition size - - if ( part.partSize.isValid() ) + if ( !entry.partSize.isValid() ) { - // We need to ignore the percent-defined - if ( part.partSize.unit() != CalamaresUtils::Partition::SizeUnit::Percent ) - { - size = part.partSize.toSectors( totalSize, dev->logicalSize() ); - } - else - { - if ( part.partMinSize.isValid() ) - { - size = part.partMinSize.toSectors( totalSize, dev->logicalSize() ); - } - else - { - size = 0; - } - } - } - else - { - cWarning() << "Partition" << part.partMountPoint << "size (" << size << "sectors) is invalid, skipping..."; + cWarning() << "Partition" << entry.partMountPoint << "size is invalid, skipping..."; continue; } - partSizeMap.insert( &part, size ); - availableSize -= size; + // Calculate partition size: Rely on "possibly uninitialized use" + // warnings to ensure that all the cases are covered below. + // We need to ignore the percent-defined until later + qint64 sectors = 0; + if ( entry.partSize.unit() != CalamaresUtils::Partition::SizeUnit::Percent ) + { + sectors = entry.partSize.toSectors( totalSectors, dev->logicalSize() ); + } + else if ( entry.partMinSize.isValid() ) + { + sectors = entry.partMinSize.toSectors( totalSectors, dev->logicalSize() ); + } + partSectorsMap.insert( &entry, sectors ); + availableSectors -= sectors; } - // Use partMinSize and see if we can do better afterward. - if ( availableSize < 0 ) + // There is not enough space for all partitions, use the min-size property + // and see if we can do better afterward. + if ( availableSectors < 0 ) { - availableSize = totalSize; - for ( const auto& part : qAsConst( m_partLayout ) ) + availableSectors = totalSectors; + for ( const auto& entry : qAsConst( m_partLayout ) ) { - qint64 size; - - if ( part.partMinSize.isValid() ) + qint64 sectors = partSectorsMap.value( &entry ); + if ( entry.partMinSize.isValid() ) { - size = part.partMinSize.toSectors( totalSize, dev->logicalSize() ); + sectors = entry.partMinSize.toSectors( totalSectors, dev->logicalSize() ); + partSectorsMap.insert( &entry, sectors ); } - else if ( part.partSize.isValid() ) - { - if ( part.partSize.unit() != CalamaresUtils::Partition::SizeUnit::Percent ) - { - size = part.partSize.toSectors( totalSize, dev->logicalSize() ); - } - else - { - size = 0; - } - } - else - { - size = 0; - } - - partSizeMap.insert( &part, size ); - availableSize -= size; + availableSectors -= sectors; } } - // Assign size for percentage-defined partitions - for ( const auto& part : qAsConst( m_partLayout ) ) + // Assign sectors for percentage-defined partitions. + for ( const auto& entry : qAsConst( m_partLayout ) ) { - if ( part.partSize.unit() == CalamaresUtils::Partition::SizeUnit::Percent ) + if ( entry.partSize.unit() == CalamaresUtils::Partition::SizeUnit::Percent ) { - qint64 size = partSizeMap.value( &part ); - size = part.partSize.toSectors( availableSize + size, dev->logicalSize() ); - if ( part.partMinSize.isValid() ) + qint64 sectors + = entry.partSize.toSectors( availableSectors + partSectorsMap.value( &entry ), dev->logicalSize() ); + if ( entry.partMinSize.isValid() ) { - qint64 minSize = part.partMinSize.toSectors( totalSize, dev->logicalSize() ); - if ( minSize > size ) - { - size = minSize; - } + sectors = std::max( sectors, entry.partMinSize.toSectors( totalSectors, dev->logicalSize() ) ); } - if ( part.partMaxSize.isValid() ) + if ( entry.partMaxSize.isValid() ) { - qint64 maxSize = part.partMaxSize.toSectors( totalSize, dev->logicalSize() ); - if ( maxSize < size ) - { - size = maxSize; - } + sectors = std::min( sectors, entry.partMaxSize.toSectors( totalSectors, dev->logicalSize() ) ); } - - partSizeMap.insert( &part, size ); + partSectorsMap.insert( &entry, sectors ); } } - availableSize = totalSize; - - // TODO: Refine partition sizes to make sure there is room for every partition - // Use a default (200-500M ?) minimum size for partition without minSize - - for ( const auto& part : qAsConst( m_partLayout ) ) + // Create the partitions. + currentSector = firstSector; + availableSectors = totalSectors; + for ( const auto& entry : qAsConst( m_partLayout ) ) { - qint64 size, end; - Partition* currentPartition = nullptr; - - size = partSizeMap.value( &part ); - - // Adjust partition size based on available space - if ( size > availableSize ) + // Adjust partition size based on available space. + qint64 sectors = partSectorsMap.value( &entry ); + sectors = std::min( sectors, availableSectors ); + if ( sectors == 0 ) { - size = availableSize; + continue; } - end = firstSector + std::max( size - 1, Q_INT64_C( 0 ) ); - + Partition* part = nullptr; if ( luksPassphrase.isEmpty() ) { - currentPartition = KPMHelpers::createNewPartition( - parent, *dev, role, part.partFileSystem, firstSector, end, KPM_PARTITION_FLAG( None ) ); + part = KPMHelpers::createNewPartition( parent, + *dev, + role, + entry.partFileSystem, + currentSector, + currentSector + sectors - 1, + KPM_PARTITION_FLAG( None ) ); } else { - currentPartition = KPMHelpers::createNewEncryptedPartition( - parent, *dev, role, part.partFileSystem, firstSector, end, luksPassphrase, KPM_PARTITION_FLAG( None ) ); + part = KPMHelpers::createNewEncryptedPartition( parent, + *dev, + role, + entry.partFileSystem, + currentSector, + currentSector + sectors - 1, + luksPassphrase, + KPM_PARTITION_FLAG( None ) ); } - PartitionInfo::setFormat( currentPartition, true ); - PartitionInfo::setMountPoint( currentPartition, part.partMountPoint ); - if ( !part.partLabel.isEmpty() ) + PartitionInfo::setFormat( part, true ); + PartitionInfo::setMountPoint( part, entry.partMountPoint ); + if ( !entry.partLabel.isEmpty() ) { - currentPartition->setLabel( part.partLabel ); - currentPartition->fileSystem().setLabel( part.partLabel ); + part->setLabel( entry.partLabel ); + part->fileSystem().setLabel( entry.partLabel ); } - if ( !part.partUUID.isEmpty() ) + if ( !entry.partUUID.isEmpty() ) { - currentPartition->setUUID( part.partUUID ); + part->setUUID( entry.partUUID ); } - if ( !part.partType.isEmpty() ) + if ( !entry.partType.isEmpty() ) { #if defined( WITH_KPMCORE42API ) - currentPartition->setType( part.partType ); + part->setType( entry.partType ); #else cWarning() << "Ignoring type; requires KPMcore >= 4.2.0."; #endif } - if ( part.partAttributes ) + if ( entry.partAttributes ) { #if defined( WITH_KPMCORE42API ) - currentPartition->setAttributes( part.partAttributes ); + part->setAttributes( entry.partAttributes ); #else cWarning() << "Ignoring attributes; requires KPMcore >= 4.2.0."; #endif } - if ( !part.partFeatures.isEmpty() ) + if ( !entry.partFeatures.isEmpty() ) { #if defined( WITH_KPMCORE42API ) - for ( const auto& k : part.partFeatures.keys() ) + for ( const auto& k : entry.partFeatures.keys() ) { - currentPartition->fileSystem().addFeature( k, part.partFeatures.value( k ) ); + part->fileSystem().addFeature( k, entry.partFeatures.value( k ) ); } #else cWarning() << "Ignoring features; requires KPMcore >= 4.2.0."; @@ -335,9 +285,9 @@ PartitionLayout::execute( Device* dev, } // Some buggy (legacy) BIOSes test if the bootflag of at least one partition is set. // Otherwise they ignore the device in boot-order, so add it here. - partList.append( currentPartition ); - firstSector = end + 1; - availableSize -= size; + partList.append( part ); + currentSector += sectors; + availableSectors -= sectors; } return partList; diff --git a/src/modules/partition/core/PartitionLayout.h b/src/modules/partition/core/PartitionLayout.h index 79dff1697..6e0c73f8f 100644 --- a/src/modules/partition/core/PartitionLayout.h +++ b/src/modules/partition/core/PartitionLayout.h @@ -34,7 +34,7 @@ public: QString partLabel; QString partUUID; QString partType; - quint64 partAttributes; + quint64 partAttributes = 0; QString partMountPoint; FileSystem::Type partFileSystem = FileSystem::Unknown; QVariantMap partFeatures; @@ -44,8 +44,29 @@ public: /// @brief All-zeroes PartitionEntry PartitionEntry(); - /// @brief Parse @p size, @p min and @p max to their respective member variables - PartitionEntry( const QString& size, const QString& min, const QString& max ); + /** @brief Parse @p mountPoint, @p size, @p minSize and @p maxSize to their respective member variables + * + * Sets a specific FS type (not parsed from string like the other + * constructor). + */ + PartitionEntry( FileSystem::Type fs, + const QString& mountPoint, + const QString& size, + const QString& minSize = QString(), + const QString& maxSize = QString() ); + /// @brief All-field PartitionEntry + PartitionEntry( const QString& label, + const QString& uuid, + const QString& type, + quint64 attributes, + const QString& mountPoint, + const QString& fs, + const QVariantMap& features, + const QString& size, + const QString& minSize = QString(), + const QString& maxSize = QString() ); + /// @brief Copy PartitionEntry + PartitionEntry( const PartitionEntry& e ) = default; bool isValid() const { @@ -59,39 +80,30 @@ public: }; PartitionLayout(); - PartitionLayout( PartitionEntry entry ); PartitionLayout( const PartitionLayout& layout ); ~PartitionLayout(); - bool addEntry( PartitionEntry entry ); - bool addEntry( const QString& mountPoint, - const QString& size, - const QString& min = QString(), - const QString& max = QString() ); - bool addEntry( const QString& label, - const QString& uuid, - const QString& type, - quint64 attributes, - const QString& mountPoint, - const QString& fs, - const QVariantMap& features, - const QString& size, - const QString& min = QString(), - const QString& max = QString() ); + /** @brief create the configuration from @p config + * + * @p config is a list of partition entries (in QVariant form, + * read from YAML). If no entries are given, then a single + * partition is created with the given @p defaultFsType + */ + void init( FileSystem::Type defaultFsType, const QVariantList& config ); + bool addEntry( const PartitionEntry& entry ); /** * @brief Apply the current partition layout to the selected drive space. * @return A list of Partition objects. */ - QList< Partition* > execute( Device* dev, - qint64 firstSector, - qint64 lastSector, - QString luksPassphrase, - PartitionNode* parent, - const PartitionRole& role ); + QList< Partition* > createPartitions( Device* dev, + qint64 firstSector, + qint64 lastSector, + QString luksPassphrase, + PartitionNode* parent, + const PartitionRole& role ); private: - FileSystem::Type m_defaultFsType; QList< PartitionEntry > m_partLayout; }; diff --git a/src/modules/partition/gui/BootInfoWidget.cpp b/src/modules/partition/gui/BootInfoWidget.cpp index 5d9dcf8b5..0b9d08c47 100644 --- a/src/modules/partition/gui/BootInfoWidget.cpp +++ b/src/modules/partition/gui/BootInfoWidget.cpp @@ -12,6 +12,7 @@ #include "core/PartUtils.h" #include "utils/CalamaresUtilsGui.h" +#include "utils/QtCompat.h" #include "utils/Retranslator.h" #include @@ -45,7 +46,7 @@ BootInfoWidget::BootInfoWidget( QWidget* parent ) m_bootLabel->setAlignment( Qt::AlignCenter ); QPalette palette; - palette.setBrush( QPalette::Foreground, QColor( "#4D4D4D" ) ); //dark grey + palette.setBrush( WindowText, QColor( "#4D4D4D" ) ); //dark grey m_bootIcon->setAutoFillBackground( true ); m_bootLabel->setAutoFillBackground( true ); diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index ac8d6fd92..35aec51e4 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -736,14 +736,12 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) return; } + // This will be deleted by the second lambda, below. QString* homePartitionPath = new QString(); - bool doReuseHomePartition = m_reuseHomeCheckBox->isChecked(); - // NOTE: using by-ref captures because we need to write homePartitionPath and - // doReuseHomePartition *after* the device revert, for later use. ScanningDialog::run( QtConcurrent::run( - [this, current]( QString* homePartitionPath, bool doReuseHomePartition ) { + [this, current, homePartitionPath]( bool doReuseHomePartition ) { QMutexLocker locker( &m_coreMutex ); if ( m_core->isDirty() ) @@ -823,9 +821,8 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) } } }, - homePartitionPath, - doReuseHomePartition ), - [=] { + m_reuseHomeCheckBox->isChecked() ), + [this, homePartitionPath] { m_reuseHomeCheckBox->setVisible( !homePartitionPath->isEmpty() ); if ( !homePartitionPath->isEmpty() ) m_reuseHomeCheckBox->setText( tr( "Reuse %1 as home partition for %2." ) @@ -845,10 +842,11 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) /** - * @brief ChoicePage::updateDeviceStatePreview clears and rebuilds the contents of the - * preview widget for the current on-disk state. This also triggers a rescan in the - * PCM to get a Device* copy that's unaffected by subsequent PCM changes. - * @param currentDevice a pointer to the selected Device. + * @brief clear and then rebuild the contents of the preview widget + * + * The preview widget for the current disk is completely re-constructed + * based on the on-disk state. This also triggers a rescan in the + * PCM to get a Device* copy that's unaffected by subsequent PCM changes. */ void ChoicePage::updateDeviceStatePreview() @@ -905,7 +903,9 @@ ChoicePage::updateDeviceStatePreview() m_beforePartitionBarsView->setSelectionMode( QAbstractItemView::SingleSelection ); m_beforePartitionLabelsView->setSelectionMode( QAbstractItemView::SingleSelection ); break; - default: + case InstallChoice::NoChoice: + case InstallChoice::Erase: + case InstallChoice::Manual: m_beforePartitionBarsView->setSelectionMode( QAbstractItemView::NoSelection ); m_beforePartitionLabelsView->setSelectionMode( QAbstractItemView::NoSelection ); } @@ -916,10 +916,10 @@ ChoicePage::updateDeviceStatePreview() /** - * @brief ChoicePage::updateActionChoicePreview clears and rebuilds the contents of the - * preview widget for the current PCM-proposed state. No rescans here, this should - * be immediate. - * @param currentDevice a pointer to the selected Device. + * @brief rebuild the contents of the preview for the PCM-proposed state. + * + * No rescans here, this should be immediate. + * * @param choice the chosen partitioning action. */ void @@ -989,7 +989,7 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) m_previewAfterFrame->show(); m_previewAfterLabel->show(); - SelectionFilter filter = [this]( const QModelIndex& index ) { + SelectionFilter filter = []( const QModelIndex& index ) { return PartUtils::canBeResized( static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ) ); }; @@ -1078,7 +1078,7 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) } else { - SelectionFilter filter = [this]( const QModelIndex& index ) { + SelectionFilter filter = []( const QModelIndex& index ) { return PartUtils::canBeReplaced( static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ) ); }; @@ -1124,7 +1124,9 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) case InstallChoice::Alongside: previewSelectionMode = QAbstractItemView::SingleSelection; break; - default: + case InstallChoice::NoChoice: + case InstallChoice::Erase: + case InstallChoice::Manual: previewSelectionMode = QAbstractItemView::NoSelection; } @@ -1178,15 +1180,15 @@ ChoicePage::setupEfiSystemPartitionSelector() QComboBox* ChoicePage::createBootloaderComboBox( QWidget* parent ) { - QComboBox* bcb = new QComboBox( parent ); - bcb->setModel( m_core->bootLoaderModel() ); + QComboBox* comboForBootloader = new QComboBox( parent ); + comboForBootloader->setModel( m_core->bootLoaderModel() ); // When the chosen bootloader device changes, we update the choice in the PCM - connect( bcb, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, [this]( int newIndex ) { - QComboBox* bcb = qobject_cast< QComboBox* >( sender() ); - if ( bcb ) + connect( comboForBootloader, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, [this]( int newIndex ) { + QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() ); + if ( bootloaderCombo ) { - QVariant var = bcb->itemData( newIndex, BootLoaderModel::BootLoaderPathRole ); + QVariant var = bootloaderCombo->itemData( newIndex, BootLoaderModel::BootLoaderPathRole ); if ( !var.isValid() ) { return; @@ -1195,7 +1197,7 @@ ChoicePage::createBootloaderComboBox( QWidget* parent ) } } ); - return bcb; + return comboForBootloader; } @@ -1219,7 +1221,6 @@ operator<<( QDebug& s, PartitionIterator& it ) * @brief ChoicePage::setupActions happens every time a new Device* is selected in the * device picker. Sets up the text and visibility of the partitioning actions based * on the currently selected Device*, bootloader and os-prober output. - * @param currentDevice */ void ChoicePage::setupActions() @@ -1464,7 +1465,7 @@ ChoicePage::setupActions() } if ( m_somethingElseButton->isHidden() && m_alongsideButton->isHidden() && m_replaceButton->isHidden() - && m_somethingElseButton->isHidden() ) + && m_eraseButton->isHidden() ) { if ( atLeastOneIsMounted ) { diff --git a/src/modules/partition/gui/ChoicePage.h b/src/modules/partition/gui/ChoicePage.h index 118f23a46..1bdee10ea 100644 --- a/src/modules/partition/gui/ChoicePage.h +++ b/src/modules/partition/gui/ChoicePage.h @@ -54,7 +54,7 @@ class ChoicePage : public QWidget, private Ui::ChoicePage Q_OBJECT public: explicit ChoicePage( Config* config, QWidget* parent = nullptr ); - virtual ~ChoicePage(); + ~ChoicePage() override; /** * @brief init runs when the PartitionViewStep and the PartitionCoreModule are diff --git a/src/modules/partition/gui/CreatePartitionDialog.h b/src/modules/partition/gui/CreatePartitionDialog.h index dc756d352..bee70f61b 100644 --- a/src/modules/partition/gui/CreatePartitionDialog.h +++ b/src/modules/partition/gui/CreatePartitionDialog.h @@ -45,7 +45,7 @@ public: Partition* partition, const QStringList& usedMountPoints, QWidget* parentWidget = nullptr ); - ~CreatePartitionDialog(); + ~CreatePartitionDialog() override; /** * Must be called when user wants to create a partition in diff --git a/src/modules/partition/gui/DeviceInfoWidget.cpp b/src/modules/partition/gui/DeviceInfoWidget.cpp index 80eacd05b..708982101 100644 --- a/src/modules/partition/gui/DeviceInfoWidget.cpp +++ b/src/modules/partition/gui/DeviceInfoWidget.cpp @@ -7,13 +7,13 @@ * */ - #include "DeviceInfoWidget.h" #include "GlobalStorage.h" #include "JobQueue.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" +#include "utils/QtCompat.h" #include "utils/Retranslator.h" #include @@ -47,7 +47,7 @@ DeviceInfoWidget::DeviceInfoWidget( QWidget* parent ) m_ptLabel->setAlignment( Qt::AlignCenter ); QPalette palette; - palette.setBrush( QPalette::Foreground, QColor( "#4D4D4D" ) ); //dark grey + palette.setBrush( WindowText, QColor( "#4D4D4D" ) ); //dark grey m_ptIcon->setAutoFillBackground( true ); m_ptLabel->setAutoFillBackground( true ); diff --git a/src/modules/partition/gui/EditExistingPartitionDialog.cpp b/src/modules/partition/gui/EditExistingPartitionDialog.cpp index 1e66c539c..3de6e0c4c 100644 --- a/src/modules/partition/gui/EditExistingPartitionDialog.cpp +++ b/src/modules/partition/gui/EditExistingPartitionDialog.cpp @@ -136,8 +136,8 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) bool partResizedMoved = newFirstSector != m_partition->firstSector() || newLastSector != m_partition->lastSector(); cDebug() << "old boundaries:" << m_partition->firstSector() << m_partition->lastSector() << m_partition->length(); - cDebug() << "new boundaries:" << newFirstSector << newLastSector; - cDebug() << "dirty status:" << m_partitionSizeController->isDirty(); + cDebug() << Logger::SubEntry << "new boundaries:" << newFirstSector << newLastSector; + cDebug() << Logger::SubEntry << "dirty status:" << m_partitionSizeController->isDirty(); FileSystem::Type fsType = FileSystem::Unknown; if ( m_ui->formatRadioButton->isChecked() ) @@ -147,6 +147,9 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) : FileSystem::typeForName( m_ui->fileSystemComboBox->currentText() ); } + const auto resultFlags = newFlags(); + const auto currentFlags = PartitionInfo::flags( m_partition ); + if ( partResizedMoved ) { if ( m_ui->formatRadioButton->isChecked() ) @@ -157,20 +160,20 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) fsType, newFirstSector, newLastSector, - newFlags() ); + resultFlags ); PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) ); PartitionInfo::setFormat( newPartition, true ); core->deletePartition( m_device, m_partition ); core->createPartition( m_device, newPartition ); - core->setPartitionFlags( m_device, newPartition, newFlags() ); + core->setPartitionFlags( m_device, newPartition, resultFlags ); } else { core->resizePartition( m_device, m_partition, newFirstSector, newLastSector ); - if ( m_partition->activeFlags() != newFlags() ) + if ( currentFlags != resultFlags ) { - core->setPartitionFlags( m_device, m_partition, newFlags() ); + core->setPartitionFlags( m_device, m_partition, resultFlags ); } } } @@ -183,9 +186,9 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) if ( m_partition->fileSystem().type() == fsType ) { core->formatPartition( m_device, m_partition ); - if ( m_partition->activeFlags() != newFlags() ) + if ( currentFlags != resultFlags ) { - core->setPartitionFlags( m_device, m_partition, newFlags() ); + core->setPartitionFlags( m_device, m_partition, resultFlags ); } } else // otherwise, we delete and recreate the partition with new fs type @@ -196,22 +199,22 @@ EditExistingPartitionDialog::applyChanges( PartitionCoreModule* core ) fsType, m_partition->firstSector(), m_partition->lastSector(), - newFlags() ); + resultFlags ); PartitionInfo::setMountPoint( newPartition, PartitionInfo::mountPoint( m_partition ) ); PartitionInfo::setFormat( newPartition, true ); core->deletePartition( m_device, m_partition ); core->createPartition( m_device, newPartition ); - core->setPartitionFlags( m_device, newPartition, newFlags() ); + core->setPartitionFlags( m_device, newPartition, resultFlags ); } } else { - core->refreshPartition( m_device, m_partition ); - if ( m_partition->activeFlags() != newFlags() ) + if ( currentFlags != resultFlags ) { - core->setPartitionFlags( m_device, m_partition, newFlags() ); + core->setPartitionFlags( m_device, m_partition, resultFlags ); } + core->refreshPartition( m_device, m_partition ); } } } diff --git a/src/modules/partition/gui/EditExistingPartitionDialog.h b/src/modules/partition/gui/EditExistingPartitionDialog.h index 96cc2c4c4..89b5b55e4 100644 --- a/src/modules/partition/gui/EditExistingPartitionDialog.h +++ b/src/modules/partition/gui/EditExistingPartitionDialog.h @@ -36,7 +36,7 @@ public: Partition* partition, const QStringList& usedMountPoints, QWidget* parentWidget = nullptr ); - ~EditExistingPartitionDialog(); + ~EditExistingPartitionDialog() override; void applyChanges( PartitionCoreModule* module ); diff --git a/src/modules/partition/gui/PartitionPage.h b/src/modules/partition/gui/PartitionPage.h index 26c7dbccf..81c2cd983 100644 --- a/src/modules/partition/gui/PartitionPage.h +++ b/src/modules/partition/gui/PartitionPage.h @@ -34,7 +34,7 @@ class PartitionPage : public QWidget Q_OBJECT public: explicit PartitionPage( PartitionCoreModule* core, QWidget* parent = nullptr ); - ~PartitionPage(); + ~PartitionPage() override; void onRevertClicked(); diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 20c7d0f08..561fdaba7 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -34,6 +34,7 @@ #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" #include "utils/NamedEnum.h" +#include "utils/QtCompat.h" #include "utils/Retranslator.h" #include "utils/Variant.h" #include "widgets/WaitingWidget.h" @@ -273,7 +274,7 @@ PartitionViewStep::createSummaryWidget() const jobsLabel->setText( jobsLines.join( "
" ) ); jobsLabel->setMargin( CalamaresUtils::defaultFontHeight() / 2 ); QPalette pal; - pal.setColor( QPalette::Background, pal.window().color().lighter( 108 ) ); + pal.setColor( WindowBackground, pal.window().color().lighter( 108 ) ); jobsLabel->setAutoFillBackground( true ); jobsLabel->setPalette( pal ); } @@ -542,6 +543,12 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) gs->insert( "efiSystemPartitionName", CalamaresUtils::getString( configurationMap, "efiSystemPartitionName" ) ); } + // Read and parse key swapPartitionName + if ( configurationMap.contains( "swapPartitionName" ) ) + { + gs->insert( "swapPartitionName", CalamaresUtils::getString( configurationMap, "swapPartitionName" ) ); + } + // OTHER SETTINGS // gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) ); @@ -595,14 +602,8 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); m_future->setFuture( future ); - if ( configurationMap.contains( "partitionLayout" ) ) - { - m_core->initLayout( configurationMap.value( "partitionLayout" ).toList() ); - } - else - { - m_core->initLayout(); - } + m_core->initLayout( fsType == FileSystem::Unknown ? FileSystem::Ext4 : fsType, + configurationMap.value( "partitionLayout" ).toList() ); } diff --git a/src/modules/partition/gui/ReplaceWidget.h b/src/modules/partition/gui/ReplaceWidget.h index 5277e5626..fbd19b429 100644 --- a/src/modules/partition/gui/ReplaceWidget.h +++ b/src/modules/partition/gui/ReplaceWidget.h @@ -27,7 +27,7 @@ class ReplaceWidget : public QWidget Q_OBJECT public: explicit ReplaceWidget( PartitionCoreModule* core, QComboBox* devicesComboBox, QWidget* parent = nullptr ); - virtual ~ReplaceWidget(); + virtual ~ReplaceWidget() override; bool isNextEnabled() const; diff --git a/src/modules/partition/gui/VolumeGroupBaseDialog.h b/src/modules/partition/gui/VolumeGroupBaseDialog.h index 253160d97..94ed0b98b 100644 --- a/src/modules/partition/gui/VolumeGroupBaseDialog.h +++ b/src/modules/partition/gui/VolumeGroupBaseDialog.h @@ -30,7 +30,7 @@ class VolumeGroupBaseDialog : public QDialog public: explicit VolumeGroupBaseDialog( QString& vgName, QVector< const Partition* > pvList, QWidget* parent = nullptr ); - ~VolumeGroupBaseDialog(); + ~VolumeGroupBaseDialog() override; protected: virtual void updateOkButton(); diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp index 8e7958e83..5384cf243 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp +++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp @@ -105,7 +105,7 @@ mapForPartition( Partition* partition, const QString& uuid ) using TR = Logger::DebugRow< const char* const, const QString& >; deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode() << TR( "partlabel", map[ "partlabel" ].toString() ) << TR( "partuuid", map[ "partuuid" ].toString() ) - << TR( "parttype", map[ "partype" ].toString() ) << TR( "partattrs", map[ "partattrs" ].toString() ) + << TR( "parttype", map[ "parttype" ].toString() ) << TR( "partattrs", map[ "partattrs" ].toString() ) << TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() ) << TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid ) << TR( "claimed", map[ "claimed" ].toString() ); @@ -153,7 +153,7 @@ FillGlobalStorageJob::prettyDescription() const QString path = partitionMap.value( "device" ).toString(); QString mountPoint = partitionMap.value( "mountPoint" ).toString(); QString fsType = partitionMap.value( "fs" ).toString(); - if ( mountPoint.isEmpty() || fsType.isEmpty() ) + if ( mountPoint.isEmpty() || fsType.isEmpty() || fsType == QString( "unformatted" ) ) { continue; } diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index bfedddfca..e5de69659 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -12,7 +12,8 @@ efiSystemPartition: "/boot/efi" # If nothing is specified, the default size of 300MiB will be used. # efiSystemPartitionSize: 300M -# This optional setting specifies the name of the EFI system partition. +# This optional setting specifies the name of the EFI system partition (see +# PARTLABEL; gpt only; requires KPMCore >= 4.2.0). # If nothing is specified, the partition name is left unset. # efiSystemPartitionName: EFI @@ -48,6 +49,11 @@ userSwapChoices: # - reuse # Re-use existing swap, but don't create any (unsupported right now) - file # To swap file instead of partition +# This optional setting specifies the name of the swap partition (see +# PARTLABEL; gpt only; requires KPMCore >= 4.2.0). +# If nothing is specified, the partition name is left unset. +# swapPartitionName: swap + # LEGACY SETTINGS (these will generate a warning) # ensureSuspendToDisk: true # neverCreateSwap: false @@ -154,7 +160,19 @@ defaultFileSystemType: "ext4" # If nothing is specified, LUKS is enabled in automated modes. #enableLuksAutomatedPartitioning: true -# To apply a custom partition layout, it has to be defined this way : +# Partition layout. +# +# This optional setting specifies a custom partition layout. +# +# If nothing is specified, the default partition layout is a single partition +# for root that uses 100% of the space and uses the filesystem defined by +# defaultFileSystemType. +# +# Note: the EFI system partition is prepend automatically to the layout if +# needed; the swap partition is appended to the layout if enabled (small of +# suspend). +# +# Otherwise, the partition layout is defined as follow: # # partitionLayout: # - name: "rootfs" @@ -189,8 +207,8 @@ defaultFileSystemType: "ext4" # - uuid: partition uuid (optional parameter; gpt only; requires KPMCore >= 4.2.0) # - type: partition type (optional parameter; gpt only; requires KPMCore >= 4.2.0) # - attributes: partition attributes (optional parameter; gpt only; requires KPMCore >= 4.2.0) -# - filesystem: filesystem type -# - mountPoint: partition mount point +# - filesystem: filesystem type (optional parameter; fs not created if "unformatted" or unset) +# - mountPoint: partition mount point (optional parameter; not mounted if unset) # - size: partition size in bytes (append 'K', 'M' or 'G' for KiB, MiB or GiB) # or # % of the available drive space if a '%' is appended to the value diff --git a/src/modules/partition/tests/CreateLayoutsTests.cpp b/src/modules/partition/tests/CreateLayoutsTests.cpp index 7589b5b65..216bfc209 100644 --- a/src/modules/partition/tests/CreateLayoutsTests.cpp +++ b/src/modules/partition/tests/CreateLayoutsTests.cpp @@ -15,10 +15,6 @@ #include "partition/KPMManager.h" #include "utils/Logger.h" -#include -#include -#include - #include #include @@ -28,7 +24,8 @@ class SmartStatus; QTEST_GUILESS_MAIN( CreateLayoutsTests ) -CalamaresUtils::Partition::KPMManager* kpmcore = nullptr; +static CalamaresUtils::Partition::KPMManager* kpmcore = nullptr; +static Calamares::JobQueue* jobqueue = nullptr; using CalamaresUtils::operator""_MiB; using CalamaresUtils::operator""_GiB; @@ -43,7 +40,7 @@ CreateLayoutsTests::CreateLayoutsTests() void CreateLayoutsTests::init() { - std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) ); + jobqueue = new Calamares::JobQueue( nullptr ); kpmcore = new CalamaresUtils::Partition::KPMManager(); } @@ -51,6 +48,7 @@ void CreateLayoutsTests::cleanup() { delete kpmcore; + delete jobqueue; } void @@ -61,12 +59,13 @@ CreateLayoutsTests::testFixedSizePartition() PartitionRole role( PartitionRole::Role::Any ); QList< Partition* > partitions; - if ( !layout.addEntry( QString( "/" ), QString( "5MiB" ) ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "5MiB" ) } ) ) { QFAIL( qPrintable( "Unable to create / partition" ) ); } - partitions = layout.execute( static_cast< Device* >( &dev ), 0, dev.totalLogical(), nullptr, nullptr, role ); + partitions + = layout.createPartitions( static_cast< Device* >( &dev ), 0, dev.totalLogical(), nullptr, nullptr, role ); QCOMPARE( partitions.count(), 1 ); @@ -81,12 +80,13 @@ CreateLayoutsTests::testPercentSizePartition() PartitionRole role( PartitionRole::Role::Any ); QList< Partition* > partitions; - if ( !layout.addEntry( QString( "/" ), QString( "50%" ) ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "50%" ) } ) ) { QFAIL( qPrintable( "Unable to create / partition" ) ); } - partitions = layout.execute( static_cast< Device* >( &dev ), 0, dev.totalLogical(), nullptr, nullptr, role ); + partitions + = layout.createPartitions( static_cast< Device* >( &dev ), 0, dev.totalLogical(), nullptr, nullptr, role ); QCOMPARE( partitions.count(), 1 ); @@ -101,22 +101,23 @@ CreateLayoutsTests::testMixedSizePartition() PartitionRole role( PartitionRole::Role::Any ); QList< Partition* > partitions; - if ( !layout.addEntry( QString( "/" ), QString( "5MiB" ) ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/" ), QString( "5MiB" ) } ) ) { QFAIL( qPrintable( "Unable to create / partition" ) ); } - if ( !layout.addEntry( QString( "/home" ), QString( "50%" ) ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/home" ), QString( "50%" ) } ) ) { QFAIL( qPrintable( "Unable to create /home partition" ) ); } - if ( !layout.addEntry( QString( "/bkup" ), QString( "50%" ) ) ) + if ( !layout.addEntry( { FileSystem::Type::Ext4, QString( "/bkup" ), QString( "50%" ) } ) ) { QFAIL( qPrintable( "Unable to create /bkup partition" ) ); } - partitions = layout.execute( static_cast< Device* >( &dev ), 0, dev.totalLogical(), nullptr, nullptr, role ); + partitions + = layout.createPartitions( static_cast< Device* >( &dev ), 0, dev.totalLogical(), nullptr, nullptr, role ); QCOMPARE( partitions.count(), 3 ); @@ -126,7 +127,7 @@ CreateLayoutsTests::testMixedSizePartition() } #ifdef WITH_KPMCORE4API -// TODO: Get a clean way to instanciate a test Device from KPMCore +// TODO: Get a clean way to instantiate a test Device from KPMCore class DevicePrivate { public: @@ -156,3 +157,5 @@ TestDevice::TestDevice( const QString& name, const qint64 logicalSectorSize, con { } #endif + +TestDevice::~TestDevice() {} diff --git a/src/modules/partition/tests/CreateLayoutsTests.h b/src/modules/partition/tests/CreateLayoutsTests.h index 98d2d8cb9..5953b06a7 100644 --- a/src/modules/partition/tests/CreateLayoutsTests.h +++ b/src/modules/partition/tests/CreateLayoutsTests.h @@ -10,14 +10,16 @@ #ifndef CLEARMOUNTSJOBTESTS_H #define CLEARMOUNTSJOBTESTS_H +#include "partition/KPMHelper.h" + #include -#include class CreateLayoutsTests : public QObject { Q_OBJECT public: CreateLayoutsTests(); + ~CreateLayoutsTests() override = default; private Q_SLOTS: void testFixedSizePartition(); @@ -31,6 +33,7 @@ class TestDevice : public Device { public: TestDevice( const QString& name, const qint64 logicalSectorSize, const qint64 totalLogicalSectors ); + ~TestDevice() override; }; #endif diff --git a/src/modules/partition/tests/PartitionJobTests.cpp b/src/modules/partition/tests/PartitionJobTests.cpp index 94eec8496..a453990c7 100644 --- a/src/modules/partition/tests/PartitionJobTests.cpp +++ b/src/modules/partition/tests/PartitionJobTests.cpp @@ -16,14 +16,12 @@ #include "jobs/CreatePartitionTableJob.h" #include "jobs/ResizePartitionJob.h" +#include "partition/KPMHelper.h" #include "partition/KPMManager.h" #include "partition/PartitionQuery.h" #include "utils/Logger.h" #include "utils/Units.h" -#include -#include - #include #include #include @@ -157,7 +155,7 @@ QueueRunner::onFailed( const QString& message, const QString& details ) QFAIL( qPrintable( msg ) ); } -CalamaresUtils::Partition::KPMManager* kpmcore = nullptr; +static CalamaresUtils::Partition::KPMManager* kpmcore = nullptr; //- PartitionJobTests ------------------------------------------------------------------ PartitionJobTests::PartitionJobTests() diff --git a/src/modules/partition/tests/PartitionJobTests.h b/src/modules/partition/tests/PartitionJobTests.h index c2c01088f..9e4455ddc 100644 --- a/src/modules/partition/tests/PartitionJobTests.h +++ b/src/modules/partition/tests/PartitionJobTests.h @@ -12,12 +12,7 @@ #include "JobQueue.h" -// CalaPM -#include -#include -#include -#include -#include +#include "partition/KPMHelper.h" // Qt #include diff --git a/src/modules/plasmalnf/PlasmaLnfJob.cpp b/src/modules/plasmalnf/PlasmaLnfJob.cpp index 0721bcd88..3b550d50a 100644 --- a/src/modules/plasmalnf/PlasmaLnfJob.cpp +++ b/src/modules/plasmalnf/PlasmaLnfJob.cpp @@ -14,36 +14,30 @@ #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" +#ifdef WITH_KCONFIG +#include +#include +#endif + PlasmaLnfJob::PlasmaLnfJob( const QString& lnfPath, const QString& id ) : m_lnfPath( lnfPath ) , m_id( id ) { } - PlasmaLnfJob::~PlasmaLnfJob() {} - QString PlasmaLnfJob::prettyName() const { return tr( "Plasma Look-and-Feel Job" ); } -QString -PlasmaLnfJob::prettyStatusMessage() const -{ - return prettyName(); -} - - Calamares::JobResult PlasmaLnfJob::exec() { - cDebug() << "Plasma Look-and-Feel Job"; - - auto system = CalamaresUtils::System::instance(); - Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + auto* system = CalamaresUtils::System::instance(); + auto* gs = Calamares::JobQueue::instance()->globalStorage(); QStringList command( { "sudo", "-E", @@ -59,8 +53,20 @@ PlasmaLnfJob::exec() int r = system->targetEnvCall( command ); if ( r ) + { return Calamares::JobResult::error( tr( "Could not select KDE Plasma Look-and-Feel package" ), tr( "Could not select KDE Plasma Look-and-Feel package" ) ); + } + +#ifdef WITH_KCONFIG + // This is a workaround for lookandfeeltool **not** writing + // the LookAndFeelPackage key in kdeglobals; this happens + // with the lnftool and Plasma 5.20 (possibly other combinations + // as well). + QString targetConfig = system->targetPath( "/home/" + gs->value( "username" ).toString() + "/.config/kdeglobals" ); + KConfigGroup cg( KSharedConfig::openConfig( targetConfig ), "KDE" ); + cg.writeEntry( "LookAndFeelPackage", m_id ); +#endif return Calamares::JobResult::ok(); } diff --git a/src/modules/plasmalnf/PlasmaLnfJob.h b/src/modules/plasmalnf/PlasmaLnfJob.h index 83360434e..4eaf81014 100644 --- a/src/modules/plasmalnf/PlasmaLnfJob.h +++ b/src/modules/plasmalnf/PlasmaLnfJob.h @@ -24,7 +24,6 @@ public: ~PlasmaLnfJob() override; QString prettyName() const override; - QString prettyStatusMessage() const override; Calamares::JobResult exec() override; diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.h b/src/modules/plasmalnf/PlasmaLnfViewStep.h index 46c24c970..74de803c9 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.h +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.h @@ -14,10 +14,6 @@ #include "utils/PluginFactory.h" #include "viewpages/ViewStep.h" -#include -#include -#include - class PlasmaLnfPage; class PLUGINDLLEXPORT PlasmaLnfViewStep : public Calamares::ViewStep diff --git a/src/modules/summary/SummaryPage.cpp b/src/modules/summary/SummaryPage.cpp index d6917d962..96781c25e 100644 --- a/src/modules/summary/SummaryPage.cpp +++ b/src/modules/summary/SummaryPage.cpp @@ -19,6 +19,7 @@ #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" +#include "utils/QtCompat.h" #include "utils/Retranslator.h" #include "viewpages/ExecutionViewStep.h" @@ -183,7 +184,7 @@ SummaryPage::createBodyLabel( const QString& text ) const QLabel* label = new QLabel; label->setMargin( CalamaresUtils::defaultFontHeight() / 2 ); QPalette pal( palette() ); - pal.setColor( QPalette::Background, palette().window().color().lighter( 108 ) ); + pal.setColor( WindowBackground, palette().window().color().lighter( 108 ) ); label->setAutoFillBackground( true ); label->setPalette( pal ); label->setText( text ); diff --git a/src/modules/tracking/Config.cpp b/src/modules/tracking/Config.cpp index f1f61edfd..0d9778c6a 100644 --- a/src/modules/tracking/Config.cpp +++ b/src/modules/tracking/Config.cpp @@ -182,10 +182,10 @@ enableLevelsBelow( Config* config, TrackingType level ) { case TrackingType::UserTracking: config->userTracking()->setTracking( TrackingStyleConfig::TrackingState::EnabledByUser ); - FALLTHRU; + [[fallthrough]]; case TrackingType::MachineTracking: config->machineTracking()->setTracking( TrackingStyleConfig::TrackingState::EnabledByUser ); - FALLTHRU; + [[fallthrough]]; case TrackingType::InstallTracking: config->installTracking()->setTracking( TrackingStyleConfig::TrackingState::EnabledByUser ); break; diff --git a/src/modules/umount/main.py b/src/modules/umount/main.py index 86ab1599a..0035a6b0f 100644 --- a/src/modules/umount/main.py +++ b/src/modules/umount/main.py @@ -39,10 +39,11 @@ def list_mounts(root_mount_point): """ lst = [] + root_mount_point = os.path.normpath(root_mount_point) for line in open("/etc/mtab").readlines(): device, mount_point, _ = line.split(" ", 2) - if mount_point.startswith(root_mount_point): + if os.path.commonprefix([root_mount_point, mount_point]) == root_mount_point: lst.append((device, mount_point)) return lst diff --git a/src/modules/unpackfs/unpackfs.schema.yaml b/src/modules/unpackfs/unpackfs.schema.yaml index 66c7c0da8..0d96fe9cb 100644 --- a/src/modules/unpackfs/unpackfs.schema.yaml +++ b/src/modules/unpackfs/unpackfs.schema.yaml @@ -17,4 +17,5 @@ properties: destination: { type: string } excludeFile: { type: string } exclude: { type: array, items: { type: string } } + weight: { type: integer, exclusiveMinimum: 0 } required: [ source , sourcefs, destination ] diff --git a/src/modules/users/CMakeLists.txt b/src/modules/users/CMakeLists.txt index 5752ae67a..2772a6b39 100644 --- a/src/modules/users/CMakeLists.txt +++ b/src/modules/users/CMakeLists.txt @@ -21,35 +21,59 @@ 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( JOB_SRC +set( _users_src + # Jobs CreateUserJob.cpp + MiscJobs.cpp SetPasswordJob.cpp SetHostNameJob.cpp -) -set( CONFIG_SRC + # Configuration CheckPWQuality.cpp Config.cpp ) +calamares_add_library( + users_internal + EXPORT_MACRO PLUGINDLLEXPORT_PRO + TARGET_TYPE STATIC + NO_INSTALL + NO_VERSION + SOURCES + ${_users_src} + LINK_LIBRARIES + Qt5::DBus + ${CRYPT_LIBRARIES} +) + calamares_add_plugin( users TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES UsersViewStep.cpp UsersPage.cpp - ${JOB_SRC} - ${CONFIG_SRC} UI page_usersetup.ui RESOURCES users.qrc LINK_PRIVATE_LIBRARIES + users_internal calamaresui ${CRYPT_LIBRARIES} ${USER_EXTRA_LIB} - Qt5::DBus SHARED_LIB ) @@ -63,10 +87,14 @@ calamares_add_test( ) calamares_add_test( - userscreatetest + usersgroupstest SOURCES - TestCreateUserJob.cpp - CreateUserJob.cpp + TestGroupInformation.cpp + ${_users_src} # Build again with test-visibility + LIBRARIES + Qt5::DBus # HostName job can use DBus to systemd + ${CRYPT_LIBRARIES} # SetPassword job uses crypt() + ${USER_EXTRA_LIB} ) calamares_add_test( @@ -82,10 +110,9 @@ calamares_add_test( userstest SOURCES Tests.cpp - ${JOB_SRC} - ${CONFIG_SRC} + ${_users_src} # Build again with test-visibility LIBRARIES - ${USER_EXTRA_LIB} Qt5::DBus # HostName job can use DBus to systemd ${CRYPT_LIBRARIES} # SetPassword job uses crypt() + ${USER_EXTRA_LIB} ) diff --git a/src/modules/users/CheckPWQuality.cpp b/src/modules/users/CheckPWQuality.cpp index 9332c6080..8dfea1f79 100644 --- a/src/modules/users/CheckPWQuality.cpp +++ b/src/modules/users/CheckPWQuality.cpp @@ -104,7 +104,6 @@ public: PWSettingsHolder() : m_settings( pwquality_default_settings() ) - , m_auxerror( nullptr ) { } @@ -113,27 +112,73 @@ public: /// Sets an option via the configuration string @p v, = style. int set( const QString& v ) { return pwquality_set_option( m_settings, v.toUtf8().constData() ); } - /// Checks the given password @p pwd against the current configuration + /** @brief Checks the given password @p pwd against the current configuration + * + * Resets m_errorString and m_errorCount and then sets them appropriately + * so that explanation() can be called afterwards. Sets m_rv as well. + */ + int check( const QString& pwd ) { void* auxerror = nullptr; - int r = pwquality_check( m_settings, pwd.toUtf8().constData(), nullptr, nullptr, &auxerror ); - m_rv = r; - return r; + m_rv = pwquality_check( m_settings, pwd.toUtf8().constData(), nullptr, nullptr, &auxerror ); + + // Positive return values could be ignored; some negative ones + // place extra information in auxerror, which is a void* and + // which needs interpretation to long- or string-values. + m_errorCount = 0; + m_errorString = QString(); + + switch ( m_rv ) + { + case PWQ_ERROR_CRACKLIB_CHECK: + if ( auxerror ) + { + /* Here the string comes from cracklib, don't free? */ + m_errorString = mungeString( auxerror ); + } + break; + case PWQ_ERROR_MEM_ALLOC: + case PWQ_ERROR_UNKNOWN_SETTING: + case PWQ_ERROR_INTEGER: + case PWQ_ERROR_NON_INT_SETTING: + case PWQ_ERROR_NON_STR_SETTING: + if ( auxerror ) + { + m_errorString = mungeString( auxerror ); + free( auxerror ); + } + break; + case PWQ_ERROR_MIN_DIGITS: + case PWQ_ERROR_MIN_UPPERS: + case PWQ_ERROR_MIN_LOWERS: + case PWQ_ERROR_MIN_OTHERS: + case PWQ_ERROR_MIN_LENGTH: + case PWQ_ERROR_MIN_CLASSES: + case PWQ_ERROR_MAX_CONSECUTIVE: + case PWQ_ERROR_MAX_CLASS_REPEAT: + case PWQ_ERROR_MAX_SEQUENCE: + if ( auxerror ) + { + m_errorCount = mungeLong( auxerror ); + } + break; + default: + break; + } + + return m_rv; } - bool hasExplanation() const { return m_rv < 0; } - - /* This is roughly the same as the function pwquality_strerror, + /** @brief Explain the results of the last call to check() + * + * This is roughly the same as the function pwquality_strerror, * only with QStrings instead, and using the Qt translation scheme. * It is used under the terms of the GNU GPL v3 or later, as * allowed by the libpwquality license (LICENSES/GPLv2+-libpwquality) */ QString explanation() { - void* auxerror = m_auxerror; - m_auxerror = nullptr; - if ( m_rv >= arbitrary_minimum_strength ) { return QString(); @@ -146,12 +191,10 @@ public: switch ( m_rv ) { case PWQ_ERROR_MEM_ALLOC: - if ( auxerror ) + if ( !m_errorString.isEmpty() ) { - QString s = QCoreApplication::translate( "PWQ", "Memory allocation error when setting '%1'" ) - .arg( mungeString( auxerror ) ); - free( auxerror ); - return s; + return QCoreApplication::translate( "PWQ", "Memory allocation error when setting '%1'" ) + .arg( m_errorString ); } return QCoreApplication::translate( "PWQ", "Memory allocation error" ); case PWQ_ERROR_SAME_PASSWORD: @@ -170,73 +213,75 @@ public: case PWQ_ERROR_BAD_WORDS: return QCoreApplication::translate( "PWQ", "The password contains forbidden words in some form" ); case PWQ_ERROR_MIN_DIGITS: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", "The password contains less than %1 digits" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password contains fewer than %n digits", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too few digits" ); case PWQ_ERROR_MIN_UPPERS: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", "The password contains less than %1 uppercase letters" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password contains fewer than %n uppercase letters", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too few uppercase letters" ); case PWQ_ERROR_MIN_LOWERS: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", "The password contains less than %1 lowercase letters" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password contains fewer than %n lowercase letters", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too few lowercase letters" ); case PWQ_ERROR_MIN_OTHERS: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", - "The password contains less than %1 non-alphanumeric characters" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password contains fewer than %n non-alphanumeric characters", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too few non-alphanumeric characters" ); case PWQ_ERROR_MIN_LENGTH: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", "The password is shorter than %1 characters" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password is shorter than %n characters", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password is too short" ); case PWQ_ERROR_ROTATED: - return QCoreApplication::translate( "PWQ", "The password is just rotated old one" ); + return QCoreApplication::translate( "PWQ", "The password is a rotated version of the previous one" ); case PWQ_ERROR_MIN_CLASSES: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", "The password contains less than %1 character classes" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password contains fewer than %n character classes", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password does not contain enough character classes" ); case PWQ_ERROR_MAX_CONSECUTIVE: - if ( auxerror ) + if ( m_errorCount ) { - return QCoreApplication::translate( "PWQ", - "The password contains more than %1 same characters consecutively" ) - .arg( mungeLong( auxerror ) ); + return QCoreApplication::translate( + "PWQ", "The password contains more than %n same characters consecutively", nullptr, m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too many same characters consecutively" ); case PWQ_ERROR_MAX_CLASS_REPEAT: - if ( auxerror ) + if ( m_errorCount ) { return QCoreApplication::translate( - "PWQ", "The password contains more than %1 characters of the same class consecutively" ) - .arg( mungeLong( auxerror ) ); + "PWQ", + "The password contains more than %n characters of the same class consecutively", + nullptr, + m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too many characters of the same class consecutively" ); case PWQ_ERROR_MAX_SEQUENCE: - if ( auxerror ) + if ( m_errorCount ) { return QCoreApplication::translate( - "PWQ", "The password contains monotonic sequence longer than %1 characters" ) - .arg( mungeLong( auxerror ) ); + "PWQ", + "The password contains monotonic sequence longer than %n characters", + nullptr, + m_errorCount ); } return QCoreApplication::translate( "PWQ", "The password contains too long of a monotonic character sequence" ); @@ -248,46 +293,34 @@ public: return QCoreApplication::translate( "PWQ", "Password generation failed - required entropy too low for settings" ); case PWQ_ERROR_CRACKLIB_CHECK: - if ( auxerror ) + if ( !m_errorString.isEmpty() ) { - /* Here the string comes from cracklib, don't free? */ return QCoreApplication::translate( "PWQ", "The password fails the dictionary check - %1" ) - .arg( mungeString( auxerror ) ); + .arg( m_errorString ); } return QCoreApplication::translate( "PWQ", "The password fails the dictionary check" ); case PWQ_ERROR_UNKNOWN_SETTING: - if ( auxerror ) + if ( !m_errorString.isEmpty() ) { - QString s = QCoreApplication::translate( "PWQ", "Unknown setting - %1" ).arg( mungeString( auxerror ) ); - free( auxerror ); - return s; + return QCoreApplication::translate( "PWQ", "Unknown setting - %1" ).arg( m_errorString ); } return QCoreApplication::translate( "PWQ", "Unknown setting" ); case PWQ_ERROR_INTEGER: - if ( auxerror ) + if ( !m_errorString.isEmpty() ) { - QString s = QCoreApplication::translate( "PWQ", "Bad integer value of setting - %1" ) - .arg( mungeString( auxerror ) ); - free( auxerror ); - return s; + return QCoreApplication::translate( "PWQ", "Bad integer value of setting - %1" ).arg( m_errorString ); } return QCoreApplication::translate( "PWQ", "Bad integer value" ); case PWQ_ERROR_NON_INT_SETTING: - if ( auxerror ) + if ( !m_errorString.isEmpty() ) { - QString s = QCoreApplication::translate( "PWQ", "Setting %1 is not of integer type" ) - .arg( mungeString( auxerror ) ); - free( auxerror ); - return s; + return QCoreApplication::translate( "PWQ", "Setting %1 is not of integer type" ).arg( m_errorString ); } return QCoreApplication::translate( "PWQ", "Setting is not of integer type" ); case PWQ_ERROR_NON_STR_SETTING: - if ( auxerror ) + if ( !m_errorString.isEmpty() ) { - QString s = QCoreApplication::translate( "PWQ", "Setting %1 is not of string type" ) - .arg( mungeString( auxerror ) ); - free( auxerror ); - return s; + return QCoreApplication::translate( "PWQ", "Setting %1 is not of string type" ).arg( m_errorString ); } return QCoreApplication::translate( "PWQ", "Setting is not of string type" ); case PWQ_ERROR_CFGFILE_OPEN: @@ -302,9 +335,11 @@ public: } private: - pwquality_settings_t* m_settings; - int m_rv; - void* m_auxerror; + QString m_errorString; ///< Textual error from last call to check() + int m_errorCount = 0; ///< Count (used in %n) error from last call to check() + int m_rv = 0; ///< Return value from libpwquality + + pwquality_settings_t* m_settings = nullptr; }; DEFINE_CHECK_FUNC( libpwquality ) diff --git a/src/modules/users/Config.cpp b/src/modules/users/Config.cpp index f8904b9d4..ba7341a9c 100644 --- a/src/modules/users/Config.cpp +++ b/src/modules/users/Config.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "CreateUserJob.h" +#include "MiscJobs.h" #include "SetHostNameJob.h" #include "SetPasswordJob.h" @@ -23,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; @@ -34,6 +47,11 @@ static void updateGSAutoLogin( bool doAutoLogin, const QString& login ) { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( !gs ) + { + cWarning() << "No Global Storage available"; + return; + } if ( doAutoLogin && !login.isEmpty() ) { @@ -85,7 +103,7 @@ Config::Config( QObject* parent ) connect( this, &Config::requireStrongPasswordsChanged, this, &Config::checkReady ); } -Config::~Config() {} +Config::~Config() { } void Config::setUserShell( const QString& shell ) @@ -95,11 +113,16 @@ Config::setUserShell( const QString& shell ) cWarning() << "User shell" << shell << "is not an absolute path."; return; } - // The shell is put into GS because the CreateUser job expects it there - auto* gs = Calamares::JobQueue::instance()->globalStorage(); - if ( gs ) + if ( shell != m_userShell ) { - gs->insert( "userShell", shell ); + m_userShell = shell; + emit userShellChanged( shell ); + // The shell is put into GS as well. + auto* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( gs ) + { + gs->insert( "userShell", shell ); + } } } @@ -117,15 +140,41 @@ insertInGlobalStorage( const QString& key, const QString& group ) void Config::setAutologinGroup( const QString& group ) { - insertInGlobalStorage( QStringLiteral( "autologinGroup" ), group ); - emit autologinGroupChanged( group ); + if ( group != m_autologinGroup ) + { + m_autologinGroup = group; + insertInGlobalStorage( QStringLiteral( "autologinGroup" ), group ); + emit autologinGroupChanged( group ); + } +} + +QStringList +Config::groupsForThisUser() const +{ + QStringList l; + l.reserve( defaultGroups().size() + 1 ); + + for ( const auto& g : defaultGroups() ) + { + l << g.name(); + } + if ( doAutoLogin() && !autologinGroup().isEmpty() ) + { + l << autologinGroup(); + } + + return l; } void Config::setSudoersGroup( const QString& group ) { - insertInGlobalStorage( QStringLiteral( "sudoersGroup" ), group ); - emit sudoersGroupChanged( group ); + if ( group != m_sudoersGroup ) + { + m_sudoersGroup = group; + insertInGlobalStorage( QStringLiteral( "sudoersGroup" ), group ); + emit sudoersGroupChanged( group ); + } } @@ -134,10 +183,9 @@ Config::setLoginName( const QString& login ) { if ( login != m_loginName ) { - updateGSAutoLogin( doAutoLogin(), login ); - m_customLoginName = !login.isEmpty(); m_loginName = login; + updateGSAutoLogin( doAutoLogin(), login ); emit loginNameChanged( login ); emit loginNameStatusChanged( loginNameStatus() ); } @@ -189,6 +237,8 @@ Config::setHostName( const QString& host ) { if ( host != m_hostName ) { + m_customHostName = !host.isEmpty(); + m_hostName = host; Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); if ( host.isEmpty() ) { @@ -198,9 +248,6 @@ Config::setHostName( const QString& host ) { gs->insert( "hostname", host ); } - - m_customHostName = !host.isEmpty(); - m_hostName = host; emit hostNameChanged( host ); emit hostNameStatusChanged( hostNameStatus() ); } @@ -279,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 ) @@ -337,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 ) @@ -369,8 +450,8 @@ Config::setAutoLogin( bool b ) { if ( b != m_doAutoLogin ) { - updateGSAutoLogin( b, loginName() ); m_doAutoLogin = b; + updateGSAutoLogin( b, loginName() ); emit autoLoginChanged( b ); } } @@ -590,16 +671,59 @@ Config::checkReady() STATICTEST void -setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups ) +setConfigurationDefaultGroups( const QVariantMap& map, QList< GroupDescription >& defaultGroups ) { - // '#' is not a valid group name; use that to distinguish an empty-list - // in the configuration (which is a legitimate, if unusual, choice) - // from a bad or missing configuration value. - defaultGroups = CalamaresUtils::getStringList( map, QStringLiteral( "defaultGroups" ), QStringList { "#" } ); - if ( defaultGroups.contains( QStringLiteral( "#" ) ) ) + defaultGroups.clear(); + + const QString key( "defaultGroups" ); + auto groupsFromConfig = map.value( key ).toList(); + if ( groupsFromConfig.isEmpty() ) { - cWarning() << "Using fallback groups. Please check *defaultGroups* in users.conf"; - defaultGroups = QStringList { "lp", "video", "network", "storage", "wheel", "audio" }; + if ( map.contains( key ) && map.value( key ).isValid() && map.value( key ).canConvert( QVariant::List ) ) + { + // Explicitly set, but empty: this is valid, but unusual. + cDebug() << key << "has explicit empty value."; + } + else + { + // By default give the user a handful of "traditional" groups, if + // none are specified at all. These are system (GID < 1000) groups. + cWarning() << "Using fallback groups. Please check *defaultGroups* value in users.conf"; + for ( const auto& s : { "lp", "video", "network", "storage", "wheel", "audio" } ) + { + defaultGroups.append( + GroupDescription( s, GroupDescription::CreateIfNeeded {}, GroupDescription::SystemGroup {} ) ); + } + } + } + else + { + for ( const auto& v : groupsFromConfig ) + { + if ( v.type() == QVariant::String ) + { + defaultGroups.append( GroupDescription( v.toString() ) ); + } + else if ( v.type() == QVariant::Map ) + { + const auto innermap = v.toMap(); + QString name = CalamaresUtils::getString( innermap, "name" ); + if ( !name.isEmpty() ) + { + defaultGroups.append( GroupDescription( name, + CalamaresUtils::getBool( innermap, "must_exist", false ), + CalamaresUtils::getBool( innermap, "system", false ) ) ); + } + else + { + cWarning() << "Ignoring *defaultGroups* entry without a name" << v; + } + } + else + { + cWarning() << "Unknown *defaultGroups* entry" << v; + } + } } } @@ -737,8 +861,16 @@ Config::createJobs() const Calamares::Job* j; - j = new CreateUserJob( - loginName(), fullName().isEmpty() ? loginName() : fullName(), doAutoLogin(), defaultGroups() ); + if ( !m_sudoersGroup.isEmpty() ) + { + j = new SetupSudoJob( m_sudoersGroup ); + jobs.append( Calamares::job_ptr( j ) ); + } + + j = new SetupGroupsJob( this ); + jobs.append( Calamares::job_ptr( j ) ); + + j = new CreateUserJob( this ); jobs.append( Calamares::job_ptr( j ) ); j = new SetPasswordJob( loginName(), userPassword() ); diff --git a/src/modules/users/Config.h b/src/modules/users/Config.h index e4057941c..d4bfee4a4 100644 --- a/src/modules/users/Config.h +++ b/src/modules/users/Config.h @@ -15,6 +15,7 @@ #include "Job.h" #include "utils/NamedEnum.h" +#include #include #include @@ -30,7 +31,61 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( HostNameActions ) const NamedEnumTable< HostNameAction >& hostNameActionNames(); -class Config : public QObject +/** @brief Settings for a single group + * + * The list of defaultgroups from the configuration can be + * set up in a fine-grained way, with both user- and system- + * level groups; this class stores a configuration for each. + */ +class GroupDescription +{ +public: + // TODO: still too-weakly typed, add a macro to define strongly-typed bools + class MustExist : public std::true_type + { + }; + class CreateIfNeeded : public std::false_type + { + }; + class SystemGroup : public std::true_type + { + }; + class UserGroup : public std::false_type + { + }; + + ///@brief An invalid, empty group + GroupDescription() {} + + ///@brief A group with full details + GroupDescription( const QString& name, bool mustExistAlready = CreateIfNeeded {}, bool isSystem = UserGroup {} ) + : m_name( name ) + , m_isValid( !name.isEmpty() ) + , m_mustAlreadyExist( mustExistAlready ) + , m_isSystem( isSystem ) + { + } + + bool isValid() const { return m_isValid; } + bool isSystemGroup() const { return m_isSystem; } + bool mustAlreadyExist() const { return m_mustAlreadyExist; } + QString name() const { return m_name; } + + ///@brief Equality of groups depends only on name and kind + bool operator==( const GroupDescription& rhs ) const + { + return rhs.name() == name() && rhs.isSystemGroup() == isSystemGroup(); + } + +private: + QString m_name; + bool m_isValid = false; + bool m_mustAlreadyExist = false; + bool m_isSystem = false; +}; + + +class PLUGINDLLEXPORT Config : public QObject { Q_OBJECT @@ -158,7 +213,12 @@ public: /// Current setting for "require strong password"? bool requireStrongPasswords() const { return m_requireStrongPasswords; } - const QStringList& defaultGroups() const { return m_defaultGroups; } + const QList< GroupDescription >& defaultGroups() const { return m_defaultGroups; } + /** @brief the names of all the groups for the current user + * + * Takes into account defaultGroups and autologin behavior. + */ + QStringList groupsForThisUser() const; // The user enters a password (and again in a separate UI element) QString userPassword() const { return m_userPassword; } @@ -242,7 +302,7 @@ private: PasswordStatus passwordStatus( const QString&, const QString& ) const; void checkReady(); - QStringList m_defaultGroups; + QList< GroupDescription > m_defaultGroups; QString m_userShell; QString m_autologinGroup; QString m_sudoersGroup; diff --git a/src/modules/users/CreateUserJob.cpp b/src/modules/users/CreateUserJob.cpp index 24b0f36d1..e08108a46 100644 --- a/src/modules/users/CreateUserJob.cpp +++ b/src/modules/users/CreateUserJob.cpp @@ -7,6 +7,8 @@ #include "CreateUserJob.h" +#include "Config.h" + #include "GlobalStorage.h" #include "JobQueue.h" #include "utils/CalamaresUtilsSystem.h" @@ -21,15 +23,9 @@ #include -CreateUserJob::CreateUserJob( const QString& userName, - const QString& fullName, - bool autologin, - const QStringList& defaultGroups ) +CreateUserJob::CreateUserJob( const Config* config ) : Calamares::Job() - , m_userName( userName ) - , m_fullName( fullName ) - , m_autologin( autologin ) - , m_defaultGroups( defaultGroups ) + , m_config( config ) { } @@ -37,68 +33,21 @@ CreateUserJob::CreateUserJob( const QString& userName, QString CreateUserJob::prettyName() const { - return tr( "Create user %1" ).arg( m_userName ); + return tr( "Create user %1" ).arg( m_config->loginName() ); } QString CreateUserJob::prettyDescription() const { - return tr( "Create user %1." ).arg( m_userName ); + return tr( "Create user %1." ).arg( m_config->loginName() ); } QString CreateUserJob::prettyStatusMessage() const { - return tr( "Creating user %1." ).arg( m_userName ); -} - -STATICTEST QStringList -groupsInTargetSystem( const QDir& targetRoot ) -{ - QFileInfo groupsFi( targetRoot.absoluteFilePath( "etc/group" ) ); - QFile groupsFile( groupsFi.absoluteFilePath() ); - if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) - { - return QStringList(); - } - QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() ); - QStringList groupsLines = groupsData.split( '\n' ); - QStringList::iterator it = groupsLines.begin(); - while ( it != groupsLines.end() ) - { - if ( it->startsWith( '#' ) ) - { - it = groupsLines.erase( it ); - continue; - } - int indexOfFirstToDrop = it->indexOf( ':' ); - if ( indexOfFirstToDrop < 1 ) - { - it = groupsLines.erase( it ); - continue; - } - it->truncate( indexOfFirstToDrop ); - ++it; - } - return groupsLines; -} - -static void -ensureGroupsExistInTarget( const QStringList& wantedGroups, const QStringList& availableGroups ) -{ - for ( const QString& group : wantedGroups ) - { - if ( !availableGroups.contains( group ) ) - { -#ifdef __FreeBSD__ - CalamaresUtils::System::instance()->targetEnvCall( { "pw", "groupadd", "-n", group } ); -#else - CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", group } ); -#endif - } - } + return m_status.isEmpty() ? tr( "Creating user %1." ).arg( m_config->loginName() ) : m_status; } static Calamares::JobResult @@ -161,47 +110,22 @@ setUserGroups( const QString& loginName, const QStringList& groups ) Calamares::JobResult CreateUserJob::exec() { - Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); - QDir destDir( gs->value( "rootMountPoint" ).toString() ); + QDir destDir; + bool reuseHome = false; - if ( gs->contains( "sudoersGroup" ) && !gs->value( "sudoersGroup" ).toString().isEmpty() ) { - cDebug() << "[CREATEUSER]: preparing sudoers"; - - QString sudoersLine = QString( "%%1 ALL=(ALL) ALL\n" ).arg( gs->value( "sudoersGroup" ).toString() ); - auto fileResult - = CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ), - sudoersLine.toUtf8().constData(), - CalamaresUtils::System::WriteMode::Overwrite ); - - if ( fileResult ) - { - if ( !CalamaresUtils::Permissions::apply( fileResult.path(), 0440 ) ) - { - return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) ); - } - } - else - { - return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) ); - } + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + destDir = QDir( gs->value( "rootMountPoint" ).toString() ); + reuseHome = gs->value( "reuseHome" ).toBool(); } - cDebug() << "[CREATEUSER]: preparing groups"; - - QStringList availableGroups = groupsInTargetSystem( destDir ); - QStringList groupsForThisUser = m_defaultGroups; - if ( m_autologin && gs->contains( "autologinGroup" ) && !gs->value( "autologinGroup" ).toString().isEmpty() ) - { - groupsForThisUser << gs->value( "autologinGroup" ).toString(); - } - ensureGroupsExistInTarget( groupsForThisUser, availableGroups ); - // If we're looking to reuse the contents of an existing /home. // This GS setting comes from the **partitioning** module. - if ( gs->value( "reuseHome" ).toBool() ) + if ( reuseHome ) { - QString shellFriendlyHome = "/home/" + m_userName; + m_status = tr( "Preserving home directory" ); + emit progress( 0.2 ); + QString shellFriendlyHome = "/home/" + m_config->loginName(); QDir existingHome( destDir.absolutePath() + shellFriendlyHome ); if ( existingHome.exists() ) { @@ -216,20 +140,26 @@ CreateUserJob::exec() cDebug() << "[CREATEUSER]: creating user"; - auto useraddResult = createUser( m_userName, m_fullName, gs->value( "userShell" ).toString() ); + m_status = tr( "Creating user %1" ).arg( m_config->loginName() ); + emit progress( 0.5 ); + auto useraddResult = createUser( m_config->loginName(), m_config->fullName(), m_config->userShell() ); if ( !useraddResult ) { return useraddResult; } - auto usergroupsResult = setUserGroups( m_userName, groupsForThisUser ); + m_status = tr( "Configuring user %1" ).arg( m_config->loginName() ); + emit progress( 0.8 ); + auto usergroupsResult = setUserGroups( m_config->loginName(), m_config->groupsForThisUser() ); if ( !usergroupsResult ) { return usergroupsResult; } - QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName ); - QString homeDir = QString( "/home/%1" ).arg( m_userName ); + m_status = tr( "Setting file permissions" ); + emit progress( 0.9 ); + QString userGroup = QString( "%1:%2" ).arg( m_config->loginName() ).arg( m_config->loginName() ); + QString homeDir = QString( "/home/%1" ).arg( m_config->loginName() ); auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( { "chown", "-R", userGroup, homeDir } ); if ( commandResult.getExitCode() ) { diff --git a/src/modules/users/CreateUserJob.h b/src/modules/users/CreateUserJob.h index 0a46198b9..28a48c886 100644 --- a/src/modules/users/CreateUserJob.h +++ b/src/modules/users/CreateUserJob.h @@ -12,23 +12,21 @@ #include "Job.h" -#include +class Config; class CreateUserJob : public Calamares::Job { Q_OBJECT public: - CreateUserJob( const QString& userName, const QString& fullName, bool autologin, const QStringList& defaultGroups ); + CreateUserJob( const Config* config ); QString prettyName() const override; QString prettyDescription() const override; QString prettyStatusMessage() const override; Calamares::JobResult exec() override; private: - QString m_userName; - QString m_fullName; - bool m_autologin; - QStringList m_defaultGroups; + const Config* m_config; + QString m_status; }; #endif /* CREATEUSERJOB_H */ diff --git a/src/modules/users/MiscJobs.cpp b/src/modules/users/MiscJobs.cpp new file mode 100644 index 000000000..c1c1d5d25 --- /dev/null +++ b/src/modules/users/MiscJobs.cpp @@ -0,0 +1,195 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#include "MiscJobs.h" + +#include "Config.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" +#include "utils/Permissions.h" + +#include +#include +#include + +SetupSudoJob::SetupSudoJob( const QString& group ) + : m_sudoGroup( group ) +{ +} + +QString +SetupSudoJob::prettyName() const +{ + return tr( "Configure
sudo
users." ); +} + +Calamares::JobResult +SetupSudoJob::exec() +{ + if ( m_sudoGroup.isEmpty() ) + { + cDebug() << "Skipping sudo 10-installer because the sudoGroup is empty."; + return Calamares::JobResult::ok(); + } + + QString sudoersLine = QString( "%%1 ALL=(ALL) ALL\n" ).arg( m_sudoGroup ); + auto fileResult + = CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ), + sudoersLine.toUtf8().constData(), + CalamaresUtils::System::WriteMode::Overwrite ); + + if ( fileResult ) + { + if ( !CalamaresUtils::Permissions::apply( fileResult.path(), 0440 ) ) + { + return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) ); + } + } + else + { + return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) ); + } + + return Calamares::JobResult::ok(); +} + +STATICTEST QStringList +groupsInTargetSystem() +{ + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( !gs ) + { + return QStringList(); + } + QDir targetRoot( gs->value( "rootMountPoint" ).toString() ); + + QFileInfo groupsFi( targetRoot.absoluteFilePath( "etc/group" ) ); + QFile groupsFile( groupsFi.absoluteFilePath() ); + if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + return QStringList(); + } + QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() ); + QStringList groupsLines = groupsData.split( '\n' ); + QStringList::iterator it = groupsLines.begin(); + while ( it != groupsLines.end() ) + { + if ( it->startsWith( '#' ) ) + { + it = groupsLines.erase( it ); + continue; + } + int indexOfFirstToDrop = it->indexOf( ':' ); + if ( indexOfFirstToDrop < 1 ) + { + it = groupsLines.erase( it ); + continue; + } + it->truncate( indexOfFirstToDrop ); + ++it; + } + return groupsLines; +} + +/** @brief Create groups in target system as needed + * + * Given a list of groups that already exist, @p availableGroups, + * go through the @p wantedGroups and create each of them. Groups that + * fail, or which should have already been there, are added to + * @p missingGroups by name. + */ +static bool +ensureGroupsExistInTarget( const QList< GroupDescription >& wantedGroups, + const QStringList& availableGroups, + QStringList& missingGroups ) +{ + int failureCount = 0; + + for ( const auto& group : wantedGroups ) + { + if ( group.isValid() && !availableGroups.contains( group.name() ) ) + { + if ( group.mustAlreadyExist() ) + { + // Should have been there already: don't create it + missingGroups.append( group.name() ); + continue; + } + + QStringList cmd; +#ifdef __FreeBSD__ + if ( group.isSystemGroup() ) + { + cWarning() << "Ignoring must-be-a-system group for" << group.name() << "on FreeBSD"; + } + cmd = QStringList { "pw", "groupadd", "-n", group.name() }; +#else + cmd << QStringLiteral( "groupadd" ); + if ( group.isSystemGroup() ) + { + cmd << "--system"; + } + cmd << group.name(); +#endif + if ( CalamaresUtils::System::instance()->targetEnvCall( cmd ) ) + { + failureCount++; + missingGroups.append( group.name() + QChar( '*' ) ); + } + } + } + if ( !missingGroups.isEmpty() ) + { + cWarning() << "Missing groups in target system (* for groupadd failure):" << Logger::DebugList( missingGroups ); + } + return failureCount == 0; +} + +SetupGroupsJob::SetupGroupsJob( const Config* config ) + : m_config( config ) +{ +} + +QString +SetupGroupsJob::prettyName() const +{ + return tr( "Preparing groups." ); +} + +Calamares::JobResult +SetupGroupsJob::exec() +{ + const auto& defaultGroups = m_config->defaultGroups(); + QStringList availableGroups = groupsInTargetSystem(); + QStringList missingGroups; + + if ( !ensureGroupsExistInTarget( defaultGroups, availableGroups, missingGroups ) ) + { + return Calamares::JobResult::error( tr( "Could not create groups in target system" ) ); + } + if ( !missingGroups.isEmpty() ) + { + return Calamares::JobResult::error( + tr( "Could not create groups in target system" ), + tr( "These groups are missing in the target system: %1" ).arg( missingGroups.join( ',' ) ) ); + } + + if ( m_config->doAutoLogin() && !m_config->autologinGroup().isEmpty() ) + { + const QString autologinGroup = m_config->autologinGroup(); + (void)ensureGroupsExistInTarget( + QList< GroupDescription >() << GroupDescription( autologinGroup ), availableGroups, missingGroups ); + } + + return Calamares::JobResult::ok(); +} diff --git a/src/modules/users/MiscJobs.h b/src/modules/users/MiscJobs.h new file mode 100644 index 000000000..fe4ff87c0 --- /dev/null +++ b/src/modules/users/MiscJobs.h @@ -0,0 +1,49 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +/**@file Various small jobs + * + * This file collects miscellaneous jobs that need to be run to prepare + * the system for the user-creation job. + */ + +#ifndef USERS_MISCJOBS_H +#define USERS_MISCJOBS_H + +#include "Job.h" + +class Config; + +class SetupSudoJob : public Calamares::Job +{ + Q_OBJECT +public: + SetupSudoJob( const QString& group ); + QString prettyName() const override; + Calamares::JobResult exec() override; + +public: + QString m_sudoGroup; +}; + +class SetupGroupsJob : public Calamares::Job +{ + Q_OBJECT + +public: + SetupGroupsJob( const Config* config ); + QString prettyName() const override; + Calamares::JobResult exec() override; + +public: + const Config* m_config; +}; + +#endif diff --git a/src/modules/users/TestCreateUserJob.cpp b/src/modules/users/TestCreateUserJob.cpp deleted file mode 100644 index fc2d74dcd..000000000 --- a/src/modules/users/TestCreateUserJob.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* === This file is part of Calamares - === - * - * SPDX-FileCopyrightText: 2020 Adriaan de Groot - * SPDX-License-Identifier: GPL-3.0-or-later - * - * Calamares is Free Software: see the License-Identifier above. - * - */ - -#include "CreateUserJob.h" - -#include "utils/Logger.h" - -#include -#include - -// Implementation details -extern QStringList groupsInTargetSystem( const QDir& targetRoot ); // CreateUserJob - -class CreateUserTests : public QObject -{ - Q_OBJECT -public: - CreateUserTests(); - ~CreateUserTests() override {} - -private Q_SLOTS: - void initTestCase(); - - void testReadGroup(); -}; - -CreateUserTests::CreateUserTests() {} - -void -CreateUserTests::initTestCase() -{ - Logger::setupLogLevel( Logger::LOGDEBUG ); - cDebug() << "Users test started."; -} - -void -CreateUserTests::testReadGroup() -{ - QDir root( "/" ); - QVERIFY( root.exists() ); - - // Get the groups in the host system - QStringList groups = groupsInTargetSystem( root ); - QVERIFY( groups.count() > 2 ); -#ifdef __FreeBSD__ - QVERIFY( groups.contains( QStringLiteral( "wheel" ) ) ); -#else - QVERIFY( groups.contains( QStringLiteral( "root" ) ) ); -#endif - // openSUSE doesn't have "sys" - // QVERIFY( groups.contains( QStringLiteral( "sys" ) ) ); - QVERIFY( groups.contains( QStringLiteral( "nogroup" ) ) ); - QVERIFY( groups.contains( QStringLiteral( "tty" ) ) ); - - for ( const QString& s : groups ) - { - QVERIFY( !s.isEmpty() ); - QVERIFY( !s.contains( '#' ) ); - } -} - -QTEST_GUILESS_MAIN( CreateUserTests ) - -#include "utils/moc-warnings.h" - -#include "TestCreateUserJob.moc" diff --git a/src/modules/users/TestGroupInformation.cpp b/src/modules/users/TestGroupInformation.cpp new file mode 100644 index 000000000..21b8d47ce --- /dev/null +++ b/src/modules/users/TestGroupInformation.cpp @@ -0,0 +1,180 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#include "Config.h" +#include "CreateUserJob.h" +#include "MiscJobs.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "utils/Logger.h" +#include "utils/Yaml.h" + +#include +#include + +// Implementation details +extern QStringList groupsInTargetSystem(); // CreateUserJob + +class GroupTests : public QObject +{ + Q_OBJECT +public: + GroupTests(); + ~GroupTests() override {} + +private Q_SLOTS: + void initTestCase(); + + void testReadGroup(); + void testCreateGroup(); + + void testSudoGroup(); + void testJobCreation(); +}; + +GroupTests::GroupTests() {} + +void +GroupTests::initTestCase() +{ + Logger::setupLogLevel( Logger::LOGDEBUG ); + cDebug() << "Users test started."; + if ( !Calamares::JobQueue::instance() ) + { + (void)new Calamares::JobQueue(); + } + Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" ); +} + +void +GroupTests::testReadGroup() +{ + // Get the groups in the host system + QStringList groups = groupsInTargetSystem(); + QVERIFY( groups.count() > 2 ); +#ifdef __FreeBSD__ + QVERIFY( groups.contains( QStringLiteral( "wheel" ) ) ); +#else + QVERIFY( groups.contains( QStringLiteral( "root" ) ) ); +#endif + // openSUSE doesn't have "sys" + // QVERIFY( groups.contains( QStringLiteral( "sys" ) ) ); + QVERIFY( groups.contains( QStringLiteral( "nogroup" ) ) ); + QVERIFY( groups.contains( QStringLiteral( "tty" ) ) ); + + for ( const QString& s : groups ) + { + QVERIFY( !s.isEmpty() ); + QVERIFY( !s.contains( '#' ) ); + } +} + +void +GroupTests::testCreateGroup() +{ + // BUILD_AS_TEST is the source-directory path + QFile fi( QString( "%1/tests/5-issue-1523.conf" ).arg( BUILD_AS_TEST ) ); + QVERIFY( fi.exists() ); + + bool ok = false; + const auto map = CalamaresUtils::loadYaml( fi, &ok ); + QVERIFY( ok ); + QVERIFY( map.count() > 0 ); // Just that it loaded, one key *defaultGroups* + + Config c; + c.setConfigurationMap( map ); + + QCOMPARE( c.defaultGroups().count(), 4 ); + QVERIFY( c.defaultGroups().contains( QStringLiteral( "adm" ) ) ); + QVERIFY( c.defaultGroups().contains( QStringLiteral( "bar" ) ) ); + + Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" ); + + SetupGroupsJob j( &c ); + QVERIFY( !j.exec() ); // running as regular user this should fail +} + +void +GroupTests::testSudoGroup() +{ + // Test programmatic changes + { + Config c; + QSignalSpy spy( &c, &Config::sudoersGroupChanged ); + QCOMPARE( c.sudoersGroup(), QString() ); + c.setSudoersGroup( QStringLiteral( "wheel" ) ); + QCOMPARE( c.sudoersGroup(), QStringLiteral( "wheel" ) ); + QCOMPARE( spy.count(), 1 ); // Changed to wheel + // Do it again, no change + c.setSudoersGroup( QStringLiteral( "wheel" ) ); + QCOMPARE( c.sudoersGroup(), QStringLiteral( "wheel" ) ); + QCOMPARE( spy.count(), 1 ); + c.setSudoersGroup( QStringLiteral( "roue" ) ); + QCOMPARE( c.sudoersGroup(), QStringLiteral( "roue" ) ); + QCOMPARE( spy.count(), 2 ); + } + + + // Test config loading + { + Config c; + QSignalSpy spy( &c, &Config::sudoersGroupChanged ); + QCOMPARE( c.sudoersGroup(), QString() ); + + QVariantMap m; + c.setConfigurationMap( m ); + QCOMPARE( c.sudoersGroup(), QString() ); + QCOMPARE( spy.count(), 0 ); // Unchanged + + const auto key = QStringLiteral( "sudoersGroup" ); + const auto v0 = QStringLiteral( "wheel" ); + const auto v1 = QStringLiteral( "roue" ); + m.insert( key, v0 ); + c.setConfigurationMap( m ); + QCOMPARE( c.sudoersGroup(), v0 ); + QCOMPARE( spy.count(), 1 ); + } +} + +/** @brief Are all the expected jobs (and no others) created? + * + * - A sudo job is created only when the sudoers group is set; + * - Groups job + * - User job + * - Password job + * - Root password job + * - Hostname job are always created. + */ +void +GroupTests::testJobCreation() +{ + const int expectedJobs = 5; + Config c; + QVERIFY( !c.isReady() ); + + // Needs some setup + c.setFullName( QStringLiteral( "Goodluck Jonathan" ) ); + c.setLoginName( QStringLiteral( "goodj" ) ); + QVERIFY( c.isReady() ); + + QCOMPARE( c.sudoersGroup(), QString() ); + QCOMPARE( c.createJobs().count(), expectedJobs ); + + c.setSudoersGroup( QStringLiteral( "wheel" ) ); + QCOMPARE( c.sudoersGroup(), QString( "wheel" ) ); + QCOMPARE( c.createJobs().count(), expectedJobs + 1 ); +} + + +QTEST_GUILESS_MAIN( GroupTests ) + +#include "utils/moc-warnings.h" + +#include "TestGroupInformation.moc" diff --git a/src/modules/users/Tests.cpp b/src/modules/users/Tests.cpp index 9ed7718c7..b687a6434 100644 --- a/src/modules/users/Tests.cpp +++ b/src/modules/users/Tests.cpp @@ -16,7 +16,7 @@ #include // Implementation details -extern void setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups ); +extern void setConfigurationDefaultGroups( const QVariantMap& map, QList< GroupDescription >& defaultGroups ); extern HostNameActions getHostNameActions( const QVariantMap& configurationMap ); extern bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks ); @@ -33,6 +33,9 @@ public: private Q_SLOTS: void initTestCase(); + // Derpy test for getting and setting regular values + void testGetSet(); + void testDefaultGroups(); void testDefaultGroupsYAML_data(); void testDefaultGroupsYAML(); @@ -50,35 +53,97 @@ UserTests::initTestCase() { Logger::setupLogLevel( Logger::LOGDEBUG ); cDebug() << "Users test started."; + + if ( !Calamares::JobQueue::instance() ) + { + (void)new Calamares::JobQueue(); + } } +void +UserTests::testGetSet() +{ + Config c; + + { + const QString sh( "/bin/sh" ); + QCOMPARE( c.userShell(), QString() ); + c.setUserShell( sh ); + QCOMPARE( c.userShell(), sh ); + c.setUserShell( sh + sh ); + QCOMPARE( c.userShell(), sh + sh ); + + const QString badsh( "bash" ); // Not absolute, that's bad + c.setUserShell( badsh ); // .. so unchanged + QCOMPARE( c.userShell(), sh + sh ); // what was set previously + + // Explicit set to empty is ok + c.setUserShell( QString() ); + QCOMPARE( c.userShell(), QString() ); + } + { + const QString al( "autolg" ); + QCOMPARE( c.autologinGroup(), QString() ); + c.setAutologinGroup( al ); + QCOMPARE( c.autologinGroup(), al ); + QVERIFY( !c.doAutoLogin() ); + c.setAutoLogin( true ); + QVERIFY( c.doAutoLogin() ); + QCOMPARE( c.autologinGroup(), al ); + } + { + const QString su( "sudogrp" ); + QCOMPARE( c.sudoersGroup(), QString() ); + c.setSudoersGroup( su ); + QCOMPARE( c.sudoersGroup(), su ); + } + { + const QString ful( "Jan-Jaap Karel Kees" ); + const QString lg( "jjkk" ); + QCOMPARE( c.fullName(), QString() ); + QCOMPARE( c.loginName(), QString() ); + QVERIFY( c.loginNameStatus().isEmpty() ); // empty login name is ok + c.setLoginName( lg ); + c.setFullName( ful ); + QVERIFY( c.loginNameStatus().isEmpty() ); // now it's still ok + QCOMPARE( c.loginName(), lg ); + QCOMPARE( c.fullName(), ful ); + c.setLoginName( "root" ); + QVERIFY( !c.loginNameStatus().isEmpty() ); // can't be root + } +} + + void UserTests::testDefaultGroups() { { - QStringList groups; + QList< GroupDescription > groups; QVariantMap hweelGroup; QVERIFY( groups.isEmpty() ); hweelGroup.insert( "defaultGroups", QStringList { "hweel" } ); setConfigurationDefaultGroups( hweelGroup, groups ); QCOMPARE( groups.count(), 1 ); - QVERIFY( groups.contains( "hweel" ) ); + QVERIFY( groups.contains( GroupDescription( "hweel" ) ) ); } { QStringList desired { "wheel", "root", "operator" }; - QStringList groups; + QList< GroupDescription > groups; QVariantMap threeGroup; QVERIFY( groups.isEmpty() ); threeGroup.insert( "defaultGroups", desired ); setConfigurationDefaultGroups( threeGroup, groups ); QCOMPARE( groups.count(), 3 ); - QVERIFY( !groups.contains( "hweel" ) ); - QCOMPARE( groups, desired ); + QVERIFY( !groups.contains( GroupDescription( "hweel" ) ) ); + for ( const auto& s : desired ) + { + QVERIFY( groups.contains( GroupDescription( s ) ) ); + } } { - QStringList groups; + QList< GroupDescription > groups; QVariantMap explicitEmpty; QVERIFY( groups.isEmpty() ); explicitEmpty.insert( "defaultGroups", QStringList() ); @@ -87,22 +152,22 @@ UserTests::testDefaultGroups() } { - QStringList groups; + QList< GroupDescription > groups; QVariantMap missing; QVERIFY( groups.isEmpty() ); setConfigurationDefaultGroups( missing, groups ); QCOMPARE( groups.count(), 6 ); // because of fallback! - QVERIFY( groups.contains( "lp" ) ); + QVERIFY( groups.contains( GroupDescription( "lp", false, GroupDescription::SystemGroup {} ) ) ); } { - QStringList groups; + QList< GroupDescription > groups; QVariantMap typeMismatch; QVERIFY( groups.isEmpty() ); typeMismatch.insert( "defaultGroups", 1 ); setConfigurationDefaultGroups( typeMismatch, groups ); QCOMPARE( groups.count(), 6 ); // because of fallback! - QVERIFY( groups.contains( "lp" ) ); + QVERIFY( groups.contains( GroupDescription( "lp", false, GroupDescription::SystemGroup {} ) ) ); } } @@ -116,6 +181,7 @@ UserTests::testDefaultGroupsYAML_data() QTest::newRow( "users.conf" ) << "users.conf" << 7 << "video"; QTest::newRow( "dashed list" ) << "tests/4-audio.conf" << 4 << "audio"; QTest::newRow( "blocked list" ) << "tests/3-wing.conf" << 3 << "wing"; + QTest::newRow( "issue 1523" ) << "tests/5-issue-1523.conf" << 4 << "foobar"; } void @@ -130,6 +196,7 @@ UserTests::testDefaultGroupsYAML() QFETCH( int, count ); QFETCH( QString, group ); + // BUILD_AS_TEST is the source-directory path QFile fi( QString( "%1/%2" ).arg( BUILD_AS_TEST, filename ) ); QVERIFY( fi.exists() ); diff --git a/src/modules/users/tests/5-issue-1523.conf b/src/modules/users/tests/5-issue-1523.conf new file mode 100644 index 000000000..a0c5e49ba --- /dev/null +++ b/src/modules/users/tests/5-issue-1523.conf @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# +--- +defaultGroups: + - adm + - name: foo + must_exist: false + system: true + - name: bar + must_exist: true + - name: foobar + must_exist: false + system: false diff --git a/src/modules/users/users.conf b/src/modules/users/users.conf index ee1ccbf1c..2e09ae123 100644 --- a/src/modules/users/users.conf +++ b/src/modules/users/users.conf @@ -3,26 +3,42 @@ # # Configuration for the one-user-system user module. # -# Besides these settings, the user module also places the following -# keys into the globalconfig area, based on user input in the view step. +# Besides these settings, the users module also places the following +# keys into the Global Storage area, based on user input in the view step. # # - hostname # - username # - password (obscured) # - autologinUser (if enabled, set to username) # -# These globalconfig keys are set when the jobs for this module -# are created. +# These Global Storage keys are set when the configuration for this module +# is read and when they are modified in the UI. --- # Used as default groups for the created user. # Adjust to your Distribution defaults. +# +# Each entry in the *defaultGroups* list is either: +# - a string, naming a group; this is a **non**-system group +# which does not need to exist in the target system; if it +# does not exist, it will be created. +# - an entry with subkeys *name*, *must_exist* and *system*; +# if the group *must_exist* and does not, an error is thrown +# and the installation fails. +# +# The group is created if it does not exist, and it is +# created as a system group (GID < 1000) or user group +# (GID >= 1000) depending on the value of *system*. defaultGroups: - - users + - name: users + must_exist: true + system: true - lp - video - network - storage - - wheel + - name: wheel + must_exist: false + system: true - audio # Some Distributions require a 'autologin' group for the user. diff --git a/src/modules/users/users.schema.yaml b/src/modules/users/users.schema.yaml index 310df350f..81088032c 100644 --- a/src/modules/users/users.schema.yaml +++ b/src/modules/users/users.schema.yaml @@ -11,7 +11,16 @@ properties: # Group settings defaultGroups: type: array - items: { type: string } + items: + oneOf: + - type: string + - type: object + properties: + name: { type: string } + must_exist: { type: boolean, default: false } + system: { type: boolean, default: false } + additionalProperties: false + required: [ name ] autologinGroup: { type: string } sudoersGroup: { type: string } # Skip login (depends on displaymanager support) diff --git a/src/modules/usersq/CMakeLists.txt b/src/modules/usersq/CMakeLists.txt index 26c270bfb..583a3384b 100644 --- a/src/modules/usersq/CMakeLists.txt +++ b/src/modules/usersq/CMakeLists.txt @@ -13,9 +13,8 @@ find_package( Crypt REQUIRED ) # Add optional libraries here set( USER_EXTRA_LIB ) -set( _users ${CMAKE_CURRENT_SOURCE_DIR}/../users ) -include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ${CMAKE_CURRENT_SOURCE_DIR}/../../libcalamares ${_users} ) +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../users ) find_package( LibPWQuality ) set_package_properties( @@ -29,19 +28,28 @@ 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 SOURCES - ${_users}/Config.cpp - ${_users}/CreateUserJob.cpp - ${_users}/SetPasswordJob.cpp UsersQmlViewStep.cpp - ${_users}/SetHostNameJob.cpp - ${_users}/CheckPWQuality.cpp RESOURCES usersq.qrc LINK_PRIVATE_LIBRARIES + users_internal calamaresui ${CRYPT_LIBRARIES} ${USER_EXTRA_LIB}