index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
author | Andreas Baumann <mail@andreasbaumann.cc> | 2022-12-01 20:27:13 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2022-12-01 20:27:13 +0100 |
commit | 26f2ccf943675505b003c12dd308dff347303362 (patch) | |
tree | 1ee556558efd3565d45c6666faa152c24e3c4d47 /archinstall | |
parent | b855d44b65a63e457e4d9d91fec98c092169b706 (diff) | |
parent | 126f56169d6faacd492b0b0f10c18762cf42a2ba (diff) |
diff --git a/archinstall/__init__.py b/archinstall/__init__.py index c6135e74..e496d213 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -37,18 +37,14 @@ from .lib.menu import Menu from .lib.menu.list_manager import ListManager from .lib.menu.text_input import TextInput from .lib.menu.global_menu import GlobalMenu -from .lib.menu.selection_menu import ( +from .lib.menu.abstract_menu import ( Selector, - GeneralMenu + AbstractMenu ) from .lib.translationhandler import TranslationHandler, DeferredTranslation from .lib.plugins import plugins, load_plugin # This initiates the plugin loading ceremony from .lib.configuration import * from .lib.udev import udevadm_info -from .lib.hsm import ( - get_fido2_devices, - fido2_enroll -) parser = ArgumentParser() __version__ = "2.5.2" diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py index 2a43174d..ad537b21 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -5,15 +5,18 @@ import logging import pathlib from typing import Optional, Dict +from .hsm.fido import Fido2 +from .models.disk_encryption import DiskEncryption from .storage import storage from .general import JSON, UNSAFE_JSON from .output import log from .exceptions import RequirementError -from .hsm import get_fido2_devices + def configuration_sanity_check(): - if storage['arguments'].get('HSM'): - if not get_fido2_devices(): + disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption') + if disk_encryption is not None and disk_encryption.hsm_device: + if not Fido2.get_fido2_devices(): raise RequirementError( f"In order to use HSM to pair with the disk encryption," + f" one needs to be accessible through /dev/hidraw* and support" @@ -21,6 +24,7 @@ def configuration_sanity_check(): + f" 'systemd-cryptenroll --fido2-device=list'." ) + class ConfigurationOutput: def __init__(self, config: Dict): """ @@ -39,8 +43,8 @@ class ConfigurationOutput: self._user_creds_file = "user_credentials.json" self._disk_layout_file = "user_disk_layout.json" - self._sensitive = ['!users', '!encryption-password'] - self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run'] + self._sensitive = ['!users'] + self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run', 'disk_encryption'] self._process_config() diff --git a/archinstall/lib/disk/encryption.py b/archinstall/lib/disk/encryption.py new file mode 100644 index 00000000..67f656c8 --- /dev/null +++ b/archinstall/lib/disk/encryption.py @@ -0,0 +1,162 @@ +from typing import Dict, Optional, Any, TYPE_CHECKING, List + +from ..menu.abstract_menu import Selector, AbstractSubMenu +from ..menu.menu import MenuSelectionType +from ..menu.table_selection_menu import TableMenu +from ..models.disk_encryption import EncryptionType, DiskEncryption +from ..user_interaction.partitioning_conf import current_partition_layout +from ..user_interaction.utils import get_password +from ..menu import Menu +from ..general import secret +from ..hsm.fido import Fido2Device, Fido2 + +if TYPE_CHECKING: + _: Any + + +class DiskEncryptionMenu(AbstractSubMenu): + def __init__(self, data_store: Dict[str, Any], preset: Optional[DiskEncryption], disk_layouts: Dict[str, Any]): + if preset: + self._preset = preset + else: + self._preset = DiskEncryption() + + self._disk_layouts = disk_layouts + super().__init__(data_store=data_store) + + def _setup_selection_menu_options(self): + self._menu_options['encryption_password'] = \ + Selector( + _('Encryption password'), + lambda x: select_encrypted_password(), + display_func=lambda x: secret(x) if x else '', + default=self._preset.encryption_password, + enabled=True + ) + self._menu_options['encryption_type'] = \ + Selector( + _('Encryption type'), + func=lambda preset: select_encryption_type(preset), + display_func=lambda x: EncryptionType.type_to_text(x) if x else None, + dependencies=['encryption_password'], + default=self._preset.encryption_type, + enabled=True + ) + self._menu_options['partitions'] = \ + Selector( + _('Partitions'), + func=lambda preset: select_partitions_to_encrypt(self._disk_layouts, preset), + display_func=lambda x: f'{len(x)} {_("Partitions")}' if x else None, + dependencies=['encryption_password'], + default=self._preset.partitions, + preview_func=self._prev_disk_layouts, + enabled=True + ) + self._menu_options['HSM'] = \ + Selector( + description=_('Use HSM to unlock encrypted drive'), + func=lambda preset: select_hsm(preset), + display_func=lambda x: self._display_hsm(x), + dependencies=['encryption_password'], + default=self._preset.hsm_device, + enabled=True + ) + + def run(self, allow_reset: bool = True) -> Optional[DiskEncryption]: + super().run(allow_reset=allow_reset) + + if self._data_store.get('encryption_password', None): + return DiskEncryption( + encryption_password=self._data_store.get('encryption_password', None), + encryption_type=self._data_store['encryption_type'], + partitions=self._data_store.get('partitions', None), + hsm_device=self._data_store.get('HSM', None) + ) + + return None + + def _display_hsm(self, device: Optional[Fido2Device]) -> Optional[str]: + if device: + return device.manufacturer + + if not Fido2.get_fido2_devices(): + return str(_('No HSM devices available')) + return None + + def _prev_disk_layouts(self) -> Optional[str]: + selector = self._menu_options['partitions'] + if selector.has_selection(): + partitions: List[Any] = selector.current_selection + output = str(_('Partitions to be encrypted')) + '\n' + output += current_partition_layout(partitions, with_title=False) + return output.rstrip() + return None + + +def select_encryption_type(preset: EncryptionType) -> Optional[EncryptionType]: + title = str(_('Select disk encryption option')) + options = [ + # _type_to_text(EncryptionType.FullDiskEncryption), + EncryptionType.type_to_text(EncryptionType.Partition) + ] + + preset_value = EncryptionType.type_to_text(preset) + choice = Menu(title, options, preset_values=preset_value).run() + + match choice.type_: + case MenuSelectionType.Reset: return None + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return EncryptionType.text_to_type(choice.value) # type: ignore + + +def select_encrypted_password() -> Optional[str]: + if passwd := get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))): + return passwd + return None + + +def select_hsm(preset: Optional[Fido2Device] = None) -> Optional[Fido2Device]: + title = _('Select a FIDO2 device to use for HSM') + fido_devices = Fido2.get_fido2_devices() + + if fido_devices: + choice = TableMenu(title, data=fido_devices).run() + match choice.type_: + case MenuSelectionType.Reset: + return None + case MenuSelectionType.Skip: + return preset + case MenuSelectionType.Selection: + return choice.value # type: ignore + + return None + + +def select_partitions_to_encrypt(disk_layouts: Dict[str, Any], preset: List[Any]) -> List[Any]: + # If no partitions was marked as encrypted, but a password was supplied and we have some disks to format.. + # Then we need to identify which partitions to encrypt. This will default to / (root). + all_partitions = [] + for blockdevice in disk_layouts.values(): + if partitions := blockdevice.get('partitions'): + partitions = [p for p in partitions if p['mountpoint'] != '/boot'] + all_partitions += partitions + + if all_partitions: + title = str(_('Select which partitions to encrypt')) + partition_table = current_partition_layout(all_partitions, with_title=False).strip() + + choice = TableMenu( + title, + table_data=(all_partitions, partition_table), + multi=True + ).run() + + match choice.type_: + case MenuSelectionType.Reset: + return [] + case MenuSelectionType.Skip: + return preset + case MenuSelectionType.Selection: + return choice.value # type: ignore + + return [] diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py index af5879aa..bdfa502a 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -5,6 +5,8 @@ import json import pathlib from typing import Optional, Dict, Any, TYPE_CHECKING # https://stackoverflow.com/a/39757388/929999 +from ..models.disk_encryption import DiskEncryption + if TYPE_CHECKING: from .blockdevice import BlockDevice _: Any @@ -107,33 +109,22 @@ class Filesystem: continue if partition.get('filesystem', {}).get('format', False): - # needed for backward compatibility with the introduction of the new "format_options" format_options = partition.get('options',[]) + partition.get('filesystem',{}).get('format_options',[]) - if partition.get('encrypted', False): + disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption') + + if partition in disk_encryption.partitions: if not partition['device_instance']: raise DiskError(f"Internal error caused us to loose the partition. Please report this issue upstream!") - if not partition.get('!password'): - if not storage['arguments'].get('!encryption-password'): - if storage['arguments'] == 'silent': - raise ValueError(f"Missing encryption password for {partition['device_instance']}") - - from ..user_interaction import get_password - - prompt = str(_('Enter a encryption password for {}').format(partition['device_instance'])) - storage['arguments']['!encryption-password'] = get_password(prompt) - - partition['!password'] = storage['arguments']['!encryption-password'] - if partition.get('mountpoint',None): loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['mountpoint']).name}loop" else: loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['device_instance'].path).name}" - partition['device_instance'].encrypt(password=partition['!password']) + partition['device_instance'].encrypt(password=disk_encryption.encryption_password) # Immediately unlock the encrypted device to format the inner volume - with luks2(partition['device_instance'], loopdev, partition['!password'], auto_unmount=True) as unlocked_device: + with luks2(partition['device_instance'], loopdev, disk_encryption.encryption_password, auto_unmount=True) as unlocked_device: if not partition.get('wipe'): if storage['arguments'] == 'silent': raise ValueError(f"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}") diff --git a/archinstall/lib/disk/helpers.py b/archinstall/lib/disk/helpers.py index 256f7abb..a5164b76 100644 --- a/archinstall/lib/disk/helpers.py +++ b/archinstall/lib/disk/helpers.py @@ -469,12 +469,6 @@ def disk_layouts() -> Optional[Dict[str, Any]]: return None -def encrypted_partitions(blockdevices :Dict[str, Any]) -> bool: - for blockdevice in blockdevices.values(): - for partition in blockdevice.get('partitions', []): - if partition.get('encrypted', False): - yield partition - def find_partition_by_mountpoint(block_devices :List[BlockDevice], relative_mountpoint :str) -> Partition: for device in block_devices: for partition in block_devices[device]['partitions']: diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py index 04d33453..9febf102 100644 --- a/archinstall/lib/disk/partition.py +++ b/archinstall/lib/disk/partition.py @@ -91,7 +91,6 @@ class Partition: self._path = path self._part_id = part_id self._target_mountpoint = mountpoint - self._encrypted = None self._encrypted = encrypted self._wipe = False self._type = 'primary' diff --git a/archinstall/lib/hsm/__init__.py b/archinstall/lib/hsm/__init__.py index c0888b04..a3f64019 100644 --- a/archinstall/lib/hsm/__init__.py +++ b/archinstall/lib/hsm/__init__.py @@ -1,4 +1 @@ -from .fido import ( - get_fido2_devices, - fido2_enroll -)
\ No newline at end of file +from .fido import Fido2 diff --git a/archinstall/lib/hsm/fido.py b/archinstall/lib/hsm/fido.py index 49f36957..4cd956a3 100644 --- a/archinstall/lib/hsm/fido.py +++ b/archinstall/lib/hsm/fido.py @@ -1,57 +1,92 @@ -import typing -import pathlib import getpass import logging + +from dataclasses import dataclass +from pathlib import Path +from typing import List + from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes from ..disk.partition import Partition from ..general import log -def get_fido2_devices() -> typing.Dict[str, typing.Dict[str, str]]: - """ - Uses systemd-cryptenroll to list the FIDO2 devices - connected that supports FIDO2. - Some devices might show up in udevadm as FIDO2 compliant - when they are in fact not. - - The drawback of systemd-cryptenroll is that it uses human readable format. - That means we get this weird table like structure that is of no use. - - So we'll look for `MANUFACTURER` and `PRODUCT`, we take their index - and we split each line based on those positions. - """ - worker = clear_vt100_escape_codes(SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8')) - - MANUFACTURER_POS = 0 - PRODUCT_POS = 0 - devices = {} - for line in worker.split('\r\n'): - if '/dev' not in line: - MANUFACTURER_POS = line.find('MANUFACTURER') - PRODUCT_POS = line.find('PRODUCT') - continue - - path = line[:MANUFACTURER_POS].rstrip() - manufacturer = line[MANUFACTURER_POS:PRODUCT_POS].rstrip() - product = line[PRODUCT_POS:] - - devices[path] = { - 'manufacturer' : manufacturer, - 'product' : product - } - - return devices - -def fido2_enroll(hsm_device_path :pathlib.Path, partition :Partition, password :str) -> bool: - worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device_path} {partition.real_device}", peak_output=True) - pw_inputted = False - pin_inputted = False - while worker.is_alive(): - if pw_inputted is False and bytes(f"please enter current passphrase for disk {partition.real_device}", 'UTF-8') in worker._trace_log.lower(): - worker.write(bytes(password, 'UTF-8')) - pw_inputted = True - - elif pin_inputted is False and bytes(f"please enter security token pin", 'UTF-8') in worker._trace_log.lower(): - worker.write(bytes(getpass.getpass(" "), 'UTF-8')) - pin_inputted = True - - log(f"You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds.", level=logging.INFO, fg="yellow")
\ No newline at end of file + +@dataclass +class Fido2Device: + path: Path + manufacturer: str + product: str + + +class Fido2: + _loaded: bool = False + _fido2_devices: List[Fido2Device] = [] + + @classmethod + def get_fido2_devices(cls, reload: bool = False) -> List[Fido2Device]: + """ + Uses systemd-cryptenroll to list the FIDO2 devices + connected that supports FIDO2. + Some devices might show up in udevadm as FIDO2 compliant + when they are in fact not. + + The drawback of systemd-cryptenroll is that it uses human readable format. + That means we get this weird table like structure that is of no use. + + So we'll look for `MANUFACTURER` and `PRODUCT`, we take their index + and we split each line based on those positions. + + Output example: + + PATH MANUFACTURER PRODUCT + /dev/hidraw1 Yubico YubiKey OTP+FIDO+CCID + """ + + # to prevent continous reloading which will slow + # down moving the cursor in the menu + if not cls._loaded or reload: + ret = SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8') + if not ret: + log('Unable to retrieve fido2 devices', level=logging.ERROR) + return [] + + fido_devices = clear_vt100_escape_codes(ret) + + manufacturer_pos = 0 + product_pos = 0 + devices = [] + + for line in fido_devices.split('\r\n'): + if '/dev' not in line: + manufacturer_pos = line.find('MANUFACTURER') + product_pos = line.find('PRODUCT') + continue + + path = line[:manufacturer_pos].rstrip() + manufacturer = line[manufacturer_pos:product_pos].rstrip() + product = line[product_pos:] + + devices.append( + Fido2Device(path, manufacturer, product) + ) + + cls._loaded = True + cls._fido2_devices = devices + + return cls._fido2_devices + + @classmethod + def fido2_enroll(cls, hsm_device: Fido2Device, partition :Partition, password :str): + worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device.path} {partition.real_device}", peak_output=True) + pw_inputted = False + pin_inputted = False + + while worker.is_alive(): + if pw_inputted is False and bytes(f"please enter current passphrase for disk {partition.real_device}", 'UTF-8') in worker._trace_log.lower(): + worker.write(bytes(password, 'UTF-8')) + pw_inputted = True + + elif pin_inputted is False and bytes(f"please enter security token pin", 'UTF-8') in worker._trace_log.lower(): + worker.write(bytes(getpass.getpass(" "), 'UTF-8')) + pin_inputted = True + + log(f"You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds.", level=logging.INFO, fg="yellow") diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 49ce4d7f..1926f593 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -15,16 +15,16 @@ from .hardware import has_uefi, is_vm, cpu_vendor from .locale_helpers import verify_keyboard_layout, verify_x11_keyboard_layout from .disk.helpers import findmnt from .mirrors import use_mirrors +from .models.disk_encryption import DiskEncryption from .plugins import plugins from .storage import storage -# from .user_interaction import * from .output import log from .profiles import Profile from .disk.partition import get_mount_fs_type from .exceptions import DiskError, ServiceException, RequirementError, HardwareIncompatibilityError, SysCallError -from .hsm import fido2_enroll from .models.users import User from .models.subvolume import Subvolume +from .hsm import Fido2 if TYPE_CHECKING: _: Any @@ -135,6 +135,8 @@ class Installer: self._zram_enabled = False + self._disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption') + def log(self, *args :str, level :int = logging.DEBUG, **kwargs :str): """ installer.log() wraps output.log() mainly to set a default log-level for this install session. @@ -196,7 +198,7 @@ class Installer: def _create_keyfile(self,luks_handle , partition :dict, password :str): """ roiutine to create keyfiles, so it can be moved elsewhere """ - if partition.get('generate-encryption-key-file'): + if self._disk_encryption.generate_encryption_file(partition): if not (cryptkey_dir := pathlib.Path(f"{self.target}/etc/cryptsetup-keys.d")).exists(): cryptkey_dir.mkdir(parents=True) # Once we store the key as ../xyzloop.key systemd-cryptsetup can automatically load this key @@ -244,26 +246,20 @@ class Installer: mount_queue = {} # we manage the encrypted partititons - for partition in [entry for entry in list_part if entry.get('encrypted', False)]: + for partition in self._disk_encryption.partitions: # open the luks device and all associate stuff - if not (password := partition.get('!password', None)) and storage['arguments'].get('!encryption-password'): - password = storage['arguments'].get('!encryption-password') - elif not password: - raise RequirementError(f"Missing partition encryption password in layout: {partition}") - loopdev = f"{storage.get('ENC_IDENTIFIER', 'ai')}{pathlib.Path(partition['device_instance'].path).name}" # note that we DON'T auto_unmount (i.e. close the encrypted device so it can be used - with (luks_handle := luks2(partition['device_instance'], loopdev, password, auto_unmount=False)) as unlocked_device: - if partition.get('generate-encryption-key-file', False) and not self._has_root(partition): - list_luks_handles.append([luks_handle, partition, password]) + with (luks_handle := luks2(partition['device_instance'], loopdev, self._disk_encryption.encryption_password, auto_unmount=False)) as unlocked_device: + if self._disk_encryption.generate_encryption_file(partition) and not self._has_root(partition): + list_luks_handles.append([luks_handle, partition, self._disk_encryption.encryption_password]) # this way all the requesrs will be to the dm_crypt device and not to the physical partition partition['device_instance'] = unlocked_device - if self._has_root(partition) and partition.get('generate-encryption-key-file', False) is False: - if storage['arguments'].get('HSM'): - hsm_device_path = storage['arguments']['HSM'] - fido2_enroll(hsm_device_path, partition['device_instance'], password) + if self._has_root(partition) and self._disk_encryption.generate_encryption_file(partition) is False: + if self._disk_encryption.hsm_device: + Fido2.fido2_enroll(self._disk_encryption.hsm_device, partition['device_instance'], self._disk_encryption.encryption_password) btrfs_subvolumes = [entry for entry in list_part if entry.get('btrfs', {}).get('subvolumes', [])] @@ -650,7 +646,7 @@ class Installer: mkinit.write(f"BINARIES=({' '.join(self.BINARIES)})\n") mkinit.write(f"FILES=({' '.join(self.FILES)})\n") - if not storage['arguments'].get('HSM'): + if not self._disk_encryption.hsm_device: # For now, if we don't use HSM we revert to the old # way of setting up encryption hooks for mkinitcpio. # This is purely for stability reasons, we're going away from this. @@ -694,7 +690,7 @@ class Installer: self.HOOKS.remove('fsck') if self.detect_encryption(partition): - if storage['arguments'].get('HSM'): + if self._disk_encryption.hsm_device: # Required bby mkinitcpio to add support for fido2-device options self.pacstrap('libfido2') @@ -758,7 +754,7 @@ class Installer: # TODO: Use python functions for this SysCommand(f'/usr/bin/arch-chroot {self.target} chmod 700 /root') - if storage['arguments'].get('HSM'): + if self._disk_encryption.hsm_device: # TODO: # A bit of a hack, but we need to get vconsole.conf in there # before running `mkinitcpio` because it expects it in HSM mode. @@ -865,9 +861,9 @@ class Installer: root_fs_type = get_mount_fs_type(root_partition.filesystem) if root_fs_type is not None: - options_entry = f'rw intel_pstate=no_hwp rootfstype={root_fs_type} {" ".join(self.KERNEL_PARAMS)}\n' + options_entry = f'rw rootfstype={root_fs_type} {" ".join(self.KERNEL_PARAMS)}\n' else: - options_entry = f'rw intel_pstate=no_hwp {" ".join(self.KERNEL_PARAMS)}\n' + options_entry = f'rw {" ".join(self.KERNEL_PARAMS)}\n' for subvolume in root_partition.subvolumes: if subvolume.root is True and subvolume.name != '<FS_TREE>': @@ -886,7 +882,7 @@ class Installer: kernel_options = f"options" - if storage['arguments'].get('HSM'): + if self._disk_encryption.hsm_device: # Note: lsblk UUID must be used, not PARTUUID for sd-encrypt to work kernel_options += f" rd.luks.name={real_device.uuid}=luksdev" # Note: tpm2-device and fido2-device don't play along very well: @@ -984,10 +980,10 @@ class Installer: # TODO: We need to detect if the encrypted device is a whole disk encryption, # or simply a partition encryption. Right now we assume it's a partition (and we always have) log(f"Identifying root partition by PART-UUID on {real_device}: '{real_device.part_uuid}'.", level=logging.DEBUG) - kernel_parameters.append(f'cryptdevice=PARTUUID={real_device.part_uuid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp rootfstype={root_fs_type} {" ".join(self.KERNEL_PARAMS)}') + kernel_parameters.append(f'cryptdevice=PARTUUID={real_device.part_uuid}:luksdev root=/dev/mapper/luksdev rw rootfstype={root_fs_type} {" ".join(self.KERNEL_PARAMS)}') else: log(f"Identifying root partition by PART-UUID on {root_partition}, looking for '{root_partition.part_uuid}'.", level=logging.DEBUG) - kernel_parameters.append(f'root=PARTUUID={root_partition.part_uuid} rw intel_pstate=no_hwp rootfstype={root_fs_type} {" ".join(self.KERNEL_PARAMS)}') + kernel_parameters.append(f'root=PARTUUID={root_partition.part_uuid} rw rootfstype={root_fs_type} {" ".join(self.KERNEL_PARAMS)}') SysCommand(f'efibootmgr --disk {boot_partition.path[:-1]} --part {boot_partition.path[-1]} --create --label "{label}" --loader {loader} --unicode \'{" ".join(kernel_parameters)}\' --verbose') diff --git a/archinstall/lib/menu/selection_menu.py b/archinstall/lib/menu/abstract_menu.py index 8a08812c..5a7ca03a 100644 --- a/archinstall/lib/menu/selection_menu.py +++ b/archinstall/lib/menu/abstract_menu.py @@ -1,16 +1,12 @@ from __future__ import annotations import logging -import sys -import pathlib from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING from .menu import Menu, MenuSelectionType from ..locale_helpers import set_keyboard_language from ..output import log from ..translationhandler import TranslationHandler, Language -from ..hsm.fido import get_fido2_devices - from ..user_interaction.general_conf import select_archinstall_language if TYPE_CHECKING: @@ -167,8 +163,9 @@ class Selector: if status and not self.is_enabled(): self.set_enabled(True) -class GeneralMenu: - def __init__(self, data_store :dict = None, auto_cursor=False, preview_size :float = 0.2): + +class AbstractMenu: + def __init__(self, data_store: Dict[str, Any] = None, auto_cursor=False, preview_size :float = 0.2): """ Create a new selection menu. @@ -196,7 +193,7 @@ class GeneralMenu: def last_choice(self): return self._last_choice - def __enter__(self, *args :Any, **kwargs :Any) -> GeneralMenu: + def __enter__(self, *args :Any, **kwargs :Any) -> AbstractMenu: self.is_context_mgr = True return self @@ -209,9 +206,9 @@ class GeneralMenu: raise args[1] for key in self._menu_options: - sel = self._menu_options[key] + selector = self._menu_options[key] if key and key not in self._data_store: - self._data_store[key] = sel._current_selection + self._data_store[key] = selector.current_selection self.exit_callback() @@ -263,8 +260,7 @@ class GeneralMenu: self._menu_options[selector_name].set_mandatory(True) self.synch(selector_name,omit_if_set) else: - print(f'No selector found: {selector_name}') - sys.exit(1) + raise ValueError(f'No selector found: {selector_name}') def _preview_display(self, selection_name: str) -> Optional[str]: config_name, selector = self._find_selection(selection_name) @@ -286,7 +282,7 @@ class GeneralMenu: selector = option[0][1] return config_name, selector - def run(self): + def run(self, allow_reset: bool = False): """ Calls the Menu framework""" # we synch all the options just in case for item in self.list_options(): @@ -304,6 +300,8 @@ class GeneralMenu: padding = self._get_menu_text_padding(list(enabled_menus.values())) menu_options = [m.menu_text(padding) for m in enabled_menus.values()] + warning_msg = str(_('All settings will be reset, are you sure?')) + selection = Menu( _('Set/Modify the below options'), menu_options, @@ -312,33 +310,39 @@ class GeneralMenu: preview_command=self._preview_display, preview_size=self.preview_size, skip_empty_entries=True, - skip=False + skip=False, + allow_reset=allow_reset, + allow_reset_warning_msg=warning_msg ).run() - if selection.type_ == MenuSelectionType.Selection: - value = selection.value + match selection.type_: + case MenuSelectionType.Reset: + self._data_store = {} + return + case MenuSelectionType.Selection: + value: str = selection.value # type: ignore - if self.auto_cursor: - cursor_pos = menu_options.index(value) + 1 # before the strip otherwise fails + if self.auto_cursor: + cursor_pos = menu_options.index(value) + 1 # before the strip otherwise fails - # in case the new position lands on a "placeholder" we'll skip them as well - while True: - if cursor_pos >= len(menu_options): - cursor_pos = 0 - if len(menu_options[cursor_pos]) > 0: - break - cursor_pos += 1 + # in case the new position lands on a "placeholder" we'll skip them as well + while True: + if cursor_pos >= len(menu_options): + cursor_pos = 0 + if len(menu_options[cursor_pos]) > 0: + break + cursor_pos += 1 - value = value.strip() + value = value.strip() - # if this calls returns false, we exit the menu - # we allow for an callback for special processing on realeasing control - if not self._process_selection(value): - break + # if this calls returns false, we exit the menu + # we allow for an callback for special processing on realeasing control + if not self._process_selection(value): + break # we get the last action key actions = {str(v.description):k for k,v in self._menu_options.items()} - self._last_choice = actions[selection.value.strip()] + self._last_choice = actions[selection.value.strip()] # type: ignore if not self.is_context_mgr: self.__exit__() @@ -472,26 +476,16 @@ class GeneralMenu: self._translation_handler.activate(language) return language - def _select_hsm(self, preset :Optional[pathlib.Path] = None) -> Optional[pathlib.Path]: - title = _('Select which partitions to mark for formatting:') - title += '\n' - - fido_devices = get_fido2_devices() - indexes = [] - for index, path in enumerate(fido_devices.keys()): - title += f"{index}: {path} ({fido_devices[path]['manufacturer']} - {fido_devices[path]['product']})" - indexes.append(f"{index}|{fido_devices[path]['product']}") +class AbstractSubMenu(AbstractMenu): + def __init__(self, data_store: Dict[str, Any] = None): + super().__init__(data_store=data_store) - title += '\n' - - choice = Menu(title, indexes, multi=False).run() - - match choice.type_: - case MenuSelectionType.Esc: return preset - case MenuSelectionType.Selection: - selection: Any = choice.value - index = int(selection.split('|',1)[0]) - return pathlib.Path(list(fido_devices.keys())[index]) - - return None + self._menu_options['__separator__'] = Selector('') + self._menu_options['back'] = \ + Selector( + _('Back'), + no_store=True, + enabled=True, + exec_func=lambda n, v: True, + ) diff --git a/archinstall/lib/menu/global_menu.py b/archinstall/lib/menu/global_menu.py index 444ba7ee..0d348227 100644 --- a/archinstall/lib/menu/global_menu.py +++ b/archinstall/lib/menu/global_menu.py @@ -3,12 +3,13 @@ from __future__ import annotations from typing import Any, List, Optional, Union, Dict, TYPE_CHECKING import archinstall -from ..disk import encrypted_partitions +from ..disk.encryption import DiskEncryptionMenu from ..general import SysCommand, secret from ..hardware import has_uefi from ..menu import Menu -from ..menu.selection_menu import Selector, GeneralMenu +from ..menu.abstract_menu import Selector, AbstractMenu from ..models import NetworkConfiguration +from ..models.disk_encryption import DiskEncryption, EncryptionType from ..models.users import User from ..output import FormattedOutput from ..profiles import is_desktop_profile, Profile @@ -25,7 +26,6 @@ from ..user_interaction import ask_to_configure_network from ..user_interaction import get_password, ask_for_a_timezone, save_config from ..user_interaction import select_additional_repositories from ..user_interaction import select_disk_layout -from ..user_interaction import select_encrypted_partitions from ..user_interaction import select_harddrives from ..user_interaction import select_kernel from ..user_interaction import select_language @@ -39,7 +39,7 @@ if TYPE_CHECKING: _: Any -class GlobalMenu(GeneralMenu): +class GlobalMenu(AbstractMenu): def __init__(self,data_store): self._disk_check = True super().__init__(data_store=data_store, auto_cursor=True, preview_size=0.3) @@ -91,18 +91,13 @@ class GlobalMenu(GeneralMenu): preview_func=self._prev_disk_layouts, display_func=lambda x: self._display_disk_layout(x), dependencies=['harddrives']) - self._menu_options['!encryption-password'] = \ + self._menu_options['disk_encryption'] = \ Selector( - _('Encryption password'), - lambda x: self._select_encrypted_password(), - display_func=lambda x: secret(x) if x else 'None', - dependencies=['harddrives']) - self._menu_options['HSM'] = Selector( - description=_('Use HSM to unlock encrypted drive'), - func=lambda preset: self._select_hsm(preset), - dependencies=['!encryption-password'], - default=None - ) + _('Disk encryption'), + lambda preset: self._disk_encryption(preset), + preview_func=self._prev_disk_encryption, + display_func=lambda x: self._display_disk_encryption(x), + dependencies=['disk_layouts']) self._menu_options['swap'] = \ Selector( _('Swap'), @@ -209,28 +204,6 @@ class GlobalMenu(GeneralMenu): def post_callback(self,name :str = None ,result :Any = None): self._update_install_text(name, result) - def exit_callback(self): - if self._data_store.get('harddrives', None) and self._data_store.get('!encryption-password', None): - # If no partitions was marked as encrypted, but a password was supplied and we have some disks to format.. - # Then we need to identify which partitions to encrypt. This will default to / (root). - if len(list(encrypted_partitions(storage['arguments'].get('disk_layouts', [])))) == 0: - for blockdevice in storage['arguments']['disk_layouts']: - if storage['arguments']['disk_layouts'][blockdevice].get('partitions'): - for partition_index in select_encrypted_partitions( - title=_('Select which partitions to encrypt:'), - partitions=storage['arguments']['disk_layouts'][blockdevice]['partitions'], - filter_=(lambda p: p['mountpoint'] != '/boot') - ): - - partition = storage['arguments']['disk_layouts'][blockdevice]['partitions'][partition_index] - partition['encrypted'] = True - partition['!password'] = storage['arguments']['!encryption-password'] - - # We make sure generate-encryption-key-file is set on additional partitions - # other than the root partition. Otherwise they won't unlock properly #1279 - if partition['mountpoint'] != '/': - partition['generate-encryption-key-file'] = True - def _install_text(self): missing = len(self._missing_configs()) if missing > 0: @@ -246,6 +219,20 @@ class GlobalMenu(GeneralMenu): else: return str(cur_value) + def _disk_encryption(self, preset: Optional[DiskEncryption]) -> Optional[DiskEncryption]: + data_store: Dict[str, Any] = {} + + selector = self._menu_options['disk_layouts'] + + if selector.has_selection(): + layouts: Dict[str, Dict[str, Any]] = selector.current_selection + else: + # this should not happen as the encryption menu has the disk layout as dependency + raise ValueError('No disk layout specified') + + disk_encryption = DiskEncryptionMenu(data_store, preset, layouts).run() + return disk_encryption + def _prev_network_config(self) -> Optional[str]: selector = self._menu_options['nic'] if selector.has_selection(): @@ -283,6 +270,30 @@ class GlobalMenu(GeneralMenu): return f'{total_nr} {_("Partitions")}' return '' + def _prev_disk_encryption(self) -> Optional[str]: + selector = self._menu_options['disk_encryption'] + if selector.has_selection(): + encryption: DiskEncryption = selector.current_selection + + enc_type = EncryptionType.type_to_text(encryption.encryption_type) + output = str(_('Encryption type')) + f': {enc_type}\n' + output += str(_('Password')) + f': {secret(encryption.encryption_password)}\n' + + if encryption.partitions: + output += 'Partitions: {} selected'.format(len(encryption.partitions)) + '\n' + + if encryption.hsm_device: + output += f'HSM: {encryption.hsm_device.manufacturer}' + + return output + + return None + + def _display_disk_encryption(self, current_value: Optional[DiskEncryption]) -> str: + if current_value: + return EncryptionType.type_to_text(current_value.encryption_type) + return '' + def _prev_install_missing_config(self) -> Optional[str]: if missing := self._missing_configs(): text = str(_('Missing configurations:\n')) @@ -327,11 +338,10 @@ class GlobalMenu(GeneralMenu): password = get_password(prompt=prompt) return password - def _select_encrypted_password(self) -> Optional[str]: - if passwd := get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))): - return passwd - else: - return None + # def _select_encrypted_password(self) -> Optional[str]: + # if passwd := get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))): + # return passwd + # return None def _select_ntp(self, preset :bool = True) -> bool: ntp = ask_ntp(preset) diff --git a/archinstall/lib/menu/list_manager.py b/archinstall/lib/menu/list_manager.py index ae3a6eb5..1e09d987 100644 --- a/archinstall/lib/menu/list_manager.py +++ b/archinstall/lib/menu/list_manager.py @@ -104,7 +104,7 @@ class ListManager: return options, header def _run_actions_on_entry(self, entry: Any): - options = self.filter_options(entry,self._sub_menu_actions) + [self._cancel_action] + options = self.filter_options(entry, self._sub_menu_actions) + [self._cancel_action] display_value = self.selected_action_display(entry) prompt = _("Select an action for '{}'").format(display_value) diff --git a/archinstall/lib/menu/menu.py b/archinstall/lib/menu/menu.py index 112bc0ae..09685c55 100644 --- a/archinstall/lib/menu/menu.py +++ b/archinstall/lib/menu/menu.py @@ -3,7 +3,7 @@ from enum import Enum, auto from os import system from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional, Callable -from archinstall.lib.menu.simple_menu import TerminalMenu +from .simple_menu import TerminalMenu from ..exceptions import RequirementError from ..output import log @@ -18,8 +18,8 @@ if TYPE_CHECKING: class MenuSelectionType(Enum): Selection = auto() - Esc = auto() - Ctrl_c = auto() + Skip = auto() + Reset = auto() @dataclass @@ -53,11 +53,11 @@ class Menu(TerminalMenu): preset_values :Union[str, List[str]] = None, cursor_index : Optional[int] = None, preview_command: Optional[Callable] = None, - preview_size: float = 0.75, + preview_size: float = 0.0, preview_title: str = 'Info', header :Union[List[str],str] = None, - raise_error_on_interrupt :bool = False, - raise_error_warning_msg :str = '', + allow_reset :bool = False, + allow_reset_warning_msg :str = '', clear_screen: bool = True, show_search_hint: bool = True, cycle_cursor: bool = True, @@ -150,17 +150,10 @@ class Menu(TerminalMenu): self._skip = skip self._default_option = default_option self._multi = multi - self._raise_error_on_interrupt = raise_error_on_interrupt - self._raise_error_warning_msg = raise_error_warning_msg + self._raise_error_on_interrupt = allow_reset + self._raise_error_warning_msg = allow_reset_warning_msg self._preview_command = preview_command - menu_title = f'\n{title}\n\n' - - if header: - if not isinstance(header,(list,tuple)): - header = [header] - menu_title += '\n'.join(header) - action_info = '' if skip: action_info += str(_('ESC to skip')) @@ -173,7 +166,15 @@ class Menu(TerminalMenu): action_info += ', ' if len(action_info) > 0 else '' action_info += str(_('TAB to select')) - menu_title += action_info + '\n' + if action_info: + action_info += '\n\n' + + menu_title = f'\n{action_info}{title}\n' + + if header: + if not isinstance(header,(list,tuple)): + header = [header] + menu_title += '\n' + '\n'.join(header) if default_option: # if a default value was specified we move that one @@ -215,7 +216,7 @@ class Menu(TerminalMenu): try: idx = self.show() except KeyboardInterrupt: - return MenuSelection(type_=MenuSelectionType.Ctrl_c) + return MenuSelection(type_=MenuSelectionType.Reset) def check_default(elem): if self._default_option is not None and f'{self._default_option} {self._default_str}' in elem: @@ -234,7 +235,7 @@ class Menu(TerminalMenu): result = check_default(self._menu_options[idx]) return MenuSelection(type_=MenuSelectionType.Selection, value=result) else: - return MenuSelection(type_=MenuSelectionType.Esc) + return MenuSelection(type_=MenuSelectionType.Skip) def _preview_wrapper(self, preview_command: Optional[Callable], current_selection: str) -> Optional[str]: if preview_command: @@ -246,15 +247,15 @@ class Menu(TerminalMenu): def run(self) -> MenuSelection: ret = self._show() - if ret.type_ == MenuSelectionType.Ctrl_c: + if ret.type_ == MenuSelectionType.Reset: if self._raise_error_on_interrupt and len(self._raise_error_warning_msg) > 0: response = Menu(self._raise_error_warning_msg, Menu.yes_no(), skip=False).run() if response.value == Menu.no(): return self.run() - - if ret.type_ is not MenuSelectionType.Selection and not self._skip: - system('clear') - return self.run() + elif ret.type_ is MenuSelectionType.Skip: + if not self._skip: + system('clear') + return self.run() return ret diff --git a/archinstall/lib/menu/table_selection_menu.py b/archinstall/lib/menu/table_selection_menu.py new file mode 100644 index 00000000..09cd6ee2 --- /dev/null +++ b/archinstall/lib/menu/table_selection_menu.py @@ -0,0 +1,107 @@ +from typing import Any, Tuple, List, Dict, Optional + +from .menu import MenuSelectionType, MenuSelection +from ..output import FormattedOutput +from ..menu import Menu + + +class TableMenu(Menu): + def __init__( + self, + title: str, + data: List[Any] = [], + table_data: Optional[Tuple[List[Any], str]] = None, + custom_menu_options: List[str] = [], + default: Any = None, + multi: bool = False + ): + """ + param title: Text that will be displayed above the menu + :type title: str + + param data: List of objects that will be displayed as rows + :type data: List + + param table_data: Tuple containing a list of objects and the corresponding + Table representation of the data as string; this can be used in case the table + has to be crafted in a more sophisticated manner + :type table_data: Optional[Tuple[List[Any], str]] + + param custom_options: List of custom options that will be displayed under the table + :type custom_menu_options: List + """ + if not data and not table_data: + raise ValueError('Either "data" or "table_data" must be provided') + + self._custom_options = custom_menu_options + self._multi = multi + + if multi: + header_padding = 7 + else: + header_padding = 2 + + if len(data): + table_text = FormattedOutput.as_table(data) + rows = table_text.split('\n') + table = self._create_table(data, rows, header_padding=header_padding) + elif table_data is not None: + # we assume the table to be + # h1 | h2 + # ----------- + # r1 | r2 + data = table_data[0] + rows = table_data[1].split('\n') + table = self._create_table(data, rows, header_padding=header_padding) + + self._options, header = self._prepare_selection(table) + + super().__init__( + title, + self._options, + header=header, + skip_empty_entries=True, + show_search_hint=False, + allow_reset=True, + multi=multi, + default_option=default + ) + + def run(self) -> MenuSelection: + choice = super().run() + + match choice.type_: + case MenuSelectionType.Selection: + if self._multi: + choice.value = [self._options[val] for val in choice.value] # type: ignore + else: + choice.value = self._options[choice.value] # type: ignore + + return choice + + def _create_table(self, data: List[Any], rows: List[str], header_padding: int = 2) -> Dict[str, Any]: + # these are the header rows of the table and do not map to any data obviously + # we're adding 2 spaces as prefix because the menu selector '> ' will be put before + # the selectable rows so the header has to be aligned + padding = ' ' * header_padding + display_data = {f'{padding}{rows[0]}': None, f'{padding}{rows[1]}': None} + + for row, entry in zip(rows[2:], data): + row = row.replace('|', '\\|') + display_data[row] = entry + + return display_data + + def _prepare_selection(self, table: Dict[str, Any]) -> Tuple[Dict[str, Any], str]: + # header rows are mapped to None so make sure to exclude those from the selectable data + options = {key: val for key, val in table.items() if val is not None} + header = '' + + if len(options) > 0: + table_header = [key for key, val in table.items() if val is None] + header = '\n'.join(table_header) + + custom = {key: None for key in self._custom_options} + options.update(custom) + + return options, header diff --git a/archinstall/lib/models/disk_encryption.py b/archinstall/lib/models/disk_encryption.py new file mode 100644 index 00000000..3edab93e --- /dev/null +++ b/archinstall/lib/models/disk_encryption.py @@ -0,0 +1,43 @@ +from dataclasses import dataclass, field +from enum import Enum, auto +from typing import Optional, List, Dict, TYPE_CHECKING, Any + +from ..hsm.fido import Fido2Device + +if TYPE_CHECKING: + _: Any + + +class EncryptionType(Enum): + Partition = auto() + # FullDiskEncryption = auto() + + @classmethod + def _encryption_type_mapper(cls) -> Dict[str, 'EncryptionType']: + return { + # str(_('Full disk encryption')): EncryptionType.FullDiskEncryption, + str(_('Partition encryption')): EncryptionType.Partition + } + + @classmethod + def text_to_type(cls, text: str) -> 'EncryptionType': + mapping = cls._encryption_type_mapper() + return mapping[text] + + @classmethod + def type_to_text(cls, type_: 'EncryptionType') -> str: + mapping = cls._encryption_type_mapper() + type_to_text = {type_: text for text, type_ in mapping.items()} + return type_to_text[type_] + + +@dataclass +class DiskEncryption: + encryption_type: EncryptionType = EncryptionType.Partition + encryption_password: str = '' + partitions: List[str] = field(default_factory=list) + hsm_device: Optional[Fido2Device] = None + + def generate_encryption_file(self, partition) -> bool: + return partition in self.partitions and partition['mountpoint'] != '/' + diff --git a/archinstall/lib/translationhandler.py b/archinstall/lib/translationhandler.py index ef33b8ec..0d74f974 100644 --- a/archinstall/lib/translationhandler.py +++ b/archinstall/lib/translationhandler.py @@ -21,15 +21,10 @@ class Language: translation: gettext.NullTranslations translation_percent: int translated_lang: Optional[str] - external_dep: Optional[str] @property def display_name(self) -> str: - if not self.external_dep and self.translated_lang: - name = self.translated_lang - else: - name = self.name_en - + name = self.name_en return f'{name} ({self.translation_percent}%)' def is_match(self, lang_or_translated_lang: str) -> bool: @@ -48,24 +43,9 @@ class TranslationHandler: self._base_pot = 'base.pot' self._languages = 'languages.json' - # check if a custom font was provided, otherwise we'll - # use one that can display latin, greek, cyrillic characters - if self.is_custom_font_enabled(): - self._set_font(self.custom_font_path().name) - else: - self._set_font('LatGrkCyr-8x16') - self._total_messages = self._get_total_active_messages() self._translated_languages = self._get_translations() - @classmethod - def custom_font_path(cls) -> Path: - return Path('/usr/share/kbd/consolefonts/archinstall_font.psfu.gz') - - @classmethod - def is_custom_font_enabled(cls) -> bool: - return cls.custom_font_path().exists() - @property def translated_languages(self) -> List[Language]: return self._translated_languages @@ -84,7 +64,6 @@ class TranslationHandler: abbr = mapping_entry['abbr'] lang = mapping_entry['lang'] translated_lang = mapping_entry.get('translated_lang', None) - external_dep = mapping_entry.get('external_dep', False) try: # get a translation for a specific language @@ -99,7 +78,7 @@ class TranslationHandler: # prevent cases where the .pot file is out of date and the percentage is above 100 percent = min(100, percent) - language = Language(abbr, lang, translation, percent, translated_lang, external_dep) + language = Language(abbr, lang, translation, percent, translated_lang) languages.append(language) except FileNotFoundError as error: raise TranslationError(f"Could not locate language file for '{lang}': {error}") @@ -110,7 +89,7 @@ class TranslationHandler: """ Set the provided font as the new terminal font """ - from archinstall import SysCommand, log + from .general import SysCommand, log try: log(f'Setting font: {font}', level=logging.DEBUG) SysCommand(f'setfont {font}') diff --git a/archinstall/lib/user_interaction/__init__.py b/archinstall/lib/user_interaction/__init__.py index a1ca2652..2bc46759 100644 --- a/archinstall/lib/user_interaction/__init__.py +++ b/archinstall/lib/user_interaction/__init__.py @@ -4,7 +4,7 @@ from .backwards_compatible_conf import generic_select, generic_multi_select from .locale_conf import select_locale_lang, select_locale_enc from .system_conf import select_kernel, select_harddrives, select_driver, ask_for_bootloader, ask_for_swap from .network_conf import ask_to_configure_network -from .partitioning_conf import select_partition, select_encrypted_partitions +from .partitioning_conf import select_partition from .general_conf import (ask_ntp, ask_for_a_timezone, ask_for_audio_selection, select_language, select_mirror_regions, select_profile, select_archinstall_language, ask_additional_packages_to_install, select_additional_repositories, ask_hostname, add_number_of_parrallel_downloads) diff --git a/archinstall/lib/user_interaction/disk_conf.py b/archinstall/lib/user_interaction/disk_conf.py index b5ed6967..554d13ef 100644 --- a/archinstall/lib/user_interaction/disk_conf.py +++ b/archinstall/lib/user_interaction/disk_conf.py @@ -45,13 +45,13 @@ def select_disk_layout(preset: Optional[Dict[str, Any]], block_devices: list, ad choice = Menu( _('Select what you wish to do with the selected block devices'), modes, - raise_error_on_interrupt=True, - raise_error_warning_msg=warning + allow_reset=True, + allow_reset_warning_msg=warning ).run() match choice.type_: - case MenuSelectionType.Esc: return preset - case MenuSelectionType.Ctrl_c: return None + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return None case MenuSelectionType.Selection: if choice.value == wipe_mode: return get_default_partition_layout(block_devices, advanced_options) @@ -77,7 +77,7 @@ def select_disk(dict_o_disks: Dict[str, BlockDevice]) -> Optional[BlockDevice]: choice = Menu(title, drives).run() - if choice.type_ == MenuSelectionType.Esc: + if choice.type_ == MenuSelectionType.Skip: return None drive = dict_o_disks[choice.value] diff --git a/archinstall/lib/user_interaction/general_conf.py b/archinstall/lib/user_interaction/general_conf.py index 6365014d..76631a98 100644 --- a/archinstall/lib/user_interaction/general_conf.py +++ b/archinstall/lib/user_interaction/general_conf.py @@ -4,19 +4,16 @@ import logging import pathlib from typing import List, Any, Optional, Dict, TYPE_CHECKING -from ..menu.menu import MenuSelectionType -from ..menu.text_input import TextInput - from ..locale_helpers import list_keyboard_languages, list_timezones from ..menu import Menu -from ..output import log -from ..profiles import Profile, list_profiles +from ..menu.menu import MenuSelectionType +from ..menu.text_input import TextInput from ..mirrors import list_mirrors - -from ..translationhandler import Language, TranslationHandler +from ..output import log from ..packages.packages import validate_package_list - +from ..profiles import Profile, list_profiles from ..storage import storage +from ..translationhandler import Language if TYPE_CHECKING: _: Any @@ -51,7 +48,7 @@ def ask_for_a_timezone(preset: str = None) -> str: ).run() match choice.type_: - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Skip: return preset case MenuSelectionType.Selection: return choice.value @@ -63,7 +60,7 @@ def ask_for_audio_selection(desktop: bool = True, preset: str = None) -> str: choice = Menu(_('Choose an audio server'), choices, preset_values=preset, default_option=default).run() match choice.type_: - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Skip: return preset case MenuSelectionType.Selection: return choice.value @@ -110,12 +107,12 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: list(mirrors.keys()), preset_values=preselected, multi=True, - raise_error_on_interrupt=True + allow_reset=True ).run() match selected_mirror.type_: - case MenuSelectionType.Ctrl_c: return {} - case MenuSelectionType.Esc: return preset_values + case MenuSelectionType.Reset: return {} + case MenuSelectionType.Skip: return preset_values case _: return {selected: mirrors[selected] for selected in selected_mirror.value} @@ -125,34 +122,22 @@ def select_archinstall_language(languages: List[Language], preset_value: Languag # name of the language in its own language options = {lang.display_name: lang for lang in languages} - def dependency_preview(current_selection: str) -> Optional[str]: - current_lang = options[current_selection] - - if current_lang.external_dep and not TranslationHandler.is_custom_font_enabled(): - font_file = TranslationHandler.custom_font_path() - text = str(_('To be able to use this translation, please install a font manually that supports the language.')) + '\n' - text += str(_('The font should be stored as {}')).format(font_file) - return text - return None + title = 'NOTE: If a language can not displayed properly, a proper font must be set manually in the console.\n' + title += 'All available fonts can be found in "/usr/share/kbd/consolefonts"\n' + title += 'e.g. setfont LatGrkCyr-8x16 (to display latin/greek/cyrillic characters)\n' choice = Menu( - _('Archinstall language'), + title, list(options.keys()), default_option=preset_value.display_name, - preview_command=lambda x: dependency_preview(x), preview_size=0.5 ).run() match choice.type_: - case MenuSelectionType.Esc: + case MenuSelectionType.Skip: return preset_value case MenuSelectionType.Selection: - language: Language = options[choice.value] - # we have to make sure that the proper AUR dependency is - # present to be able to use this language - if not language.external_dep or TranslationHandler.is_custom_font_enabled(): - return language - return select_archinstall_language(languages, preset_value) + return options[choice.value] def select_profile(preset) -> Optional[Profile]: @@ -178,21 +163,21 @@ def select_profile(preset) -> Optional[Profile]: selection = Menu( title=title, p_options=list(options.keys()), - raise_error_on_interrupt=True, - raise_error_warning_msg=warning + allow_reset=True, + allow_reset_warning_msg=warning ).run() match selection.type_: case MenuSelectionType.Selection: return options[selection.value] if selection.value is not None else None - case MenuSelectionType.Ctrl_c: + case MenuSelectionType.Reset: storage['profile_minimal'] = False storage['_selected_servers'] = [] storage['_desktop_profile'] = None storage['arguments']['desktop-environment'] = None storage['arguments']['gfx_driver_packages'] = None return None - case MenuSelectionType.Esc: + case MenuSelectionType.Skip: return None @@ -274,10 +259,10 @@ def select_additional_repositories(preset: List[str]) -> List[str]: sort=False, multi=True, preset_values=preset, - raise_error_on_interrupt=True + allow_reset=True ).run() match choice.type_: - case MenuSelectionType.Esc: return preset - case MenuSelectionType.Ctrl_c: return [] + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return [] case MenuSelectionType.Selection: return choice.value diff --git a/archinstall/lib/user_interaction/locale_conf.py b/archinstall/lib/user_interaction/locale_conf.py index 15720064..bbbe070b 100644 --- a/archinstall/lib/user_interaction/locale_conf.py +++ b/archinstall/lib/user_interaction/locale_conf.py @@ -23,7 +23,7 @@ def select_locale_lang(preset: str = None) -> str: match selected_locale.type_: case MenuSelectionType.Selection: return selected_locale.value - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Skip: return preset def select_locale_enc(preset: str = None) -> str: @@ -39,4 +39,4 @@ def select_locale_enc(preset: str = None) -> str: match selected_locale.type_: case MenuSelectionType.Selection: return selected_locale.value - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Skip: return preset diff --git a/archinstall/lib/user_interaction/network_conf.py b/archinstall/lib/user_interaction/network_conf.py index 557e8ed8..5e637f23 100644 --- a/archinstall/lib/user_interaction/network_conf.py +++ b/archinstall/lib/user_interaction/network_conf.py @@ -71,7 +71,7 @@ class ManualNetworkConfig(ListManager): available = set(all_ifaces) - set(existing_ifaces) choice = Menu(str(_('Select interface to add')), list(available), skip=True).run() - if choice.type_ == MenuSelectionType.Esc: + if choice.type_ == MenuSelectionType.Skip: return None return choice.value @@ -154,13 +154,13 @@ def ask_to_configure_network( list(network_options.values()), cursor_index=cursor_idx, sort=False, - raise_error_on_interrupt=True, - raise_error_warning_msg=warning + allow_reset=True, + allow_reset_warning_msg=warning ).run() match choice.type_: - case MenuSelectionType.Esc: return preset - case MenuSelectionType.Ctrl_c: return None + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return None if choice.value == network_options['none']: return None diff --git a/archinstall/lib/user_interaction/partitioning_conf.py b/archinstall/lib/user_interaction/partitioning_conf.py index f2e6b881..cff76dc2 100644 --- a/archinstall/lib/user_interaction/partitioning_conf.py +++ b/archinstall/lib/user_interaction/partitioning_conf.py @@ -119,7 +119,7 @@ def select_partition( choice = Menu(title, partition_indexes, multi=multiple).run() - if choice.type_ == MenuSelectionType.Esc: + if choice.type_ == MenuSelectionType.Skip: return None if isinstance(choice.value, list): @@ -150,7 +150,6 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, delete_all_partitions = str(_('Clear/Delete all partitions')) assign_mount_point = str(_('Assign mount-point for a partition')) mark_formatted = str(_('Mark/Unmark a partition to be formatted (wipes data)')) - mark_encrypted = str(_('Mark/Unmark a partition as encrypted')) mark_compressed = str(_('Mark/Unmark a partition as compressed (btrfs only)')) mark_bootable = str(_('Mark/Unmark a partition as bootable (automatic for /boot)')) set_filesystem_partition = str(_('Set desired filesystem for a partition')) @@ -167,7 +166,6 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, delete_all_partitions, assign_mount_point, mark_formatted, - mark_encrypted, mark_bootable, mark_compressed, set_filesystem_partition, @@ -207,7 +205,7 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, fs_choice = Menu(_('Enter a desired filesystem type for the partition'), fs_types()).run() - if fs_choice.type_ == MenuSelectionType.Esc: + if fs_choice.type_ == MenuSelectionType.Skip: continue prompt = str(_('Enter the start sector (percentage or block number, default: {}): ')).format( @@ -322,15 +320,6 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, # Negate the current wipe marking block_device_struct["partitions"][partition]['wipe'] = not block_device_struct["partitions"][partition].get('wipe', False) - elif task == mark_encrypted: - title = _('{}\n\nSelect which partition to mark as encrypted').format(current_layout) - partition = select_partition(title, block_device_struct["partitions"]) - - if partition is not None: - # Negate the current encryption marking - block_device_struct["partitions"][partition]['encrypted'] = \ - not block_device_struct["partitions"][partition].get('encrypted', False) - elif task == mark_bootable: title = _('{}\n\nSelect which partition to mark as bootable').format(current_layout) partition = select_partition(title, block_device_struct["partitions"]) @@ -371,30 +360,3 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, block_device_struct["partitions"][partition]['btrfs']['subvolumes'] = result return block_device_struct - - -def select_encrypted_partitions( - title :str, - partitions :List[Partition], - multiple :bool = True, - filter_ :Callable = None -) -> Optional[int, List[int]]: - partition_indexes = _get_partitions(partitions, filter_) - - if len(partition_indexes) == 0: - return None - - # show current partition layout: - if len(partitions): - title += current_partition_layout(partitions, with_idx=True) + '\n' - - choice = Menu(title, partition_indexes, multi=multiple).run() - - if choice.type_ == MenuSelectionType.Esc: - return None - - if isinstance(choice.value, list): - for partition_index in choice.value: - yield int(partition_index) - else: - yield (partition_index) diff --git a/archinstall/lib/user_interaction/save_conf.py b/archinstall/lib/user_interaction/save_conf.py index f542bc9b..d60ef995 100644 --- a/archinstall/lib/user_interaction/save_conf.py +++ b/archinstall/lib/user_interaction/save_conf.py @@ -55,7 +55,7 @@ def save_config(config: Dict): preview_command=preview ).run() - if choice.type_ == MenuSelectionType.Esc: + if choice.type_ == MenuSelectionType.Skip: return while True: diff --git a/archinstall/lib/user_interaction/system_conf.py b/archinstall/lib/user_interaction/system_conf.py index 44402a69..8454a3da 100644 --- a/archinstall/lib/user_interaction/system_conf.py +++ b/archinstall/lib/user_interaction/system_conf.py @@ -32,13 +32,13 @@ def select_kernel(preset: List[str] = None) -> List[str]: sort=True, multi=True, preset_values=preset, - raise_error_on_interrupt=True, - raise_error_warning_msg=warning + allow_reset=True, + allow_reset_warning_msg=warning ).run() match choice.type_: - case MenuSelectionType.Esc: return preset - case MenuSelectionType.Ctrl_c: return [] + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return [] case MenuSelectionType.Selection: return choice.value @@ -62,13 +62,13 @@ def select_harddrives(preset: List[str] = []) -> List[str]: list(options.keys()), preset_values=preset, multi=True, - raise_error_on_interrupt=True, - raise_error_warning_msg=warning + allow_reset=True, + allow_reset_warning_msg=warning ).run() match selected_harddrive.type_: - case MenuSelectionType.Ctrl_c: return [] - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Reset: return [] + case MenuSelectionType.Skip: return preset case MenuSelectionType.Selection: return [options[i] for i in selected_harddrive.value] @@ -132,7 +132,7 @@ def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> st ).run() match selection.type_: - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Skip: return preset case MenuSelectionType.Selection: bootloader = 'grub-install' if selection.value == Menu.yes() else bootloader else: # We use the common names for the bootloader as the selection, and map it back to the expected values. @@ -141,7 +141,7 @@ def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> st value = '' match selection.type_: - case MenuSelectionType.Esc: value = preset_val + case MenuSelectionType.Skip: value = preset_val case MenuSelectionType.Selection: value = selection.value if value != "": @@ -165,5 +165,5 @@ def ask_for_swap(preset: bool = True) -> bool: choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), preset_values=preset_val).run() match choice.type_: - case MenuSelectionType.Esc: return preset + case MenuSelectionType.Skip: return preset case MenuSelectionType.Selection: return False if choice.value == Menu.no() else True diff --git a/archinstall/locales/README.md b/archinstall/locales/README.md index cd7d794a..e1266209 100644 --- a/archinstall/locales/README.md +++ b/archinstall/locales/README.md @@ -4,19 +4,13 @@ Archinstall supports multiple languages, which depend on translations coming fro ## Important Note Before starting a new language translation be aware that a font for that language may not be -available on the ISO. We are using the pre-installed font `/usr/share/kbd/consolefonts/LatGrkCyr-8x16.psfu.gz` in archinstall -which should cover a fair amount of different languages but unfortunately not all of them. +available on the ISO. -We have the option to provide a custom font in case the above is not covering a specific language, which can -be achieved by installing the font yourself on the ISO and saving it to `/usr/share/kbd/consolefonts/archinstall_font.psfu.gz`. -If this font is present it will be automatically loaded and all languages which are not supported by the default font will -be enabled (but only some might actually work). +Fonts that are using a different character set than Latin will not be displayed correctly. If those languages +want to be selected than a proper font has to be set manually in the console. -Please make sure that the provided language works with the default font on the ISO, and if not mark it in the `languages.json` -that it needs an external dependency -``` -{"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو", "external_dep": true}, -``` +All available console fonts can be found in `/usr/share/kbd/consolefonts` and they +can be set with `setfont LatGrkCyr-8x16` ## Adding new languages @@ -49,10 +43,3 @@ msgstr "Wollen sie wirklich abbrechen?" After the translations have been written, run the script once more `./locales_generator.sh` and it will auto-generate the `base.mo` file with the included translations. After that you're all ready to go and enjoy Archinstall in the new language :) - -To display the language inside Archinstall in your own tongue, please edit the file `languages.json` and -add a `translated_lang` entry to the respective language, e.g. - -``` - {"abbr": "pl", "lang": "Polish", "translated_lang": "Polski"} -``` diff --git a/archinstall/locales/ar/LC_MESSAGES/base.po b/archinstall/locales/ar/LC_MESSAGES/base.po index 51b6c3d6..1a9fc1aa 100644 --- a/archinstall/locales/ar/LC_MESSAGES/base.po +++ b/archinstall/locales/ar/LC_MESSAGES/base.po @@ -721,7 +721,7 @@ msgstr "" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "" -msgid "Select which partitions to encrypt:" +msgid "Select which partitions to encrypt" msgstr "" msgid "very weak" diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 0b08b337..2becbbf3 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -761,7 +761,7 @@ msgstr "" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "" -msgid "Select which partitions to encrypt:" +msgid "Select which partitions to encrypt" msgstr "" msgid "very weak" @@ -835,3 +835,11 @@ msgstr "" msgid "[Default value: 0] > " msgstr "" + +msgid "" +"To be able to use this translation, please install a font manually that " +"supports the language." +msgstr "" + +msgid "The font should be stored as {}" +msgstr "" diff --git a/archinstall/locales/cs/LC_MESSAGES/base.po b/archinstall/locales/cs/LC_MESSAGES/base.po index 733c9cae..b3dea244 100644 --- a/archinstall/locales/cs/LC_MESSAGES/base.po +++ b/archinstall/locales/cs/LC_MESSAGES/base.po @@ -756,8 +756,8 @@ msgstr "Zadané uživatelské jméno není platné. Zkuste to znovu" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Má být \"{}\" superuživatelem (sudoer)?" -msgid "Select which partitions to encrypt:" -msgstr "Zvolte oddíl, který bude označen jako šifrovaný:" +msgid "Select which partitions to encrypt" +msgstr "Zvolte oddíl, který bude označen jako šifrovaný" msgid "very weak" msgstr "velmi slabé" diff --git a/archinstall/locales/de/LC_MESSAGES/base.po b/archinstall/locales/de/LC_MESSAGES/base.po index 46782bc3..dee2b481 100644 --- a/archinstall/locales/de/LC_MESSAGES/base.po +++ b/archinstall/locales/de/LC_MESSAGES/base.po @@ -776,11 +776,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Soll {} ein superuser sein (sudoer)?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Bitte wählen sie welche Partition verschlüsselt werden soll" +msgid "Select which partitions to encrypt" +msgstr "Bitte wählen sie welche Partition verschlüsselt werden soll" msgid "very weak" msgstr "" diff --git a/archinstall/locales/el/LC_MESSAGES/base.po b/archinstall/locales/el/LC_MESSAGES/base.po index 6425ba96..c41dbb7e 100644 --- a/archinstall/locales/el/LC_MESSAGES/base.po +++ b/archinstall/locales/el/LC_MESSAGES/base.po @@ -763,7 +763,7 @@ msgstr "Το όνομα χρήστη που εισάγατε δεν είναι msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Θα έπρεπε ο \"{}\" να είναι υπερχρήστης (sudo);" -msgid "Select which partitions to encrypt:" +msgid "Select which partitions to encrypt" msgstr "Επιλέξτε ποιες διαμερίσεις να κρυπτογραφηθούν." msgid "very weak" diff --git a/archinstall/locales/en/LC_MESSAGES/base.po b/archinstall/locales/en/LC_MESSAGES/base.po index 01f59274..62543eaa 100644 --- a/archinstall/locales/en/LC_MESSAGES/base.po +++ b/archinstall/locales/en/LC_MESSAGES/base.po @@ -717,7 +717,7 @@ msgstr "" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "" -msgid "Select which partitions to encrypt:" +msgid "Select which partitions to encrypt" msgstr "" msgid "very weak" diff --git a/archinstall/locales/es/LC_MESSAGES/base.po b/archinstall/locales/es/LC_MESSAGES/base.po index 3bdbe72f..f744daae 100644 --- a/archinstall/locales/es/LC_MESSAGES/base.po +++ b/archinstall/locales/es/LC_MESSAGES/base.po @@ -762,8 +762,8 @@ msgstr "El nombre de usuario que ingresó no es válido. Intente nuevamente" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "¿Debe \"{}\" ser un superusuario (sudo)?" -msgid "Select which partitions to encrypt:" -msgstr "Seleccione qué particiones cifrar:" +msgid "Select which partitions to encrypt" +msgstr "Seleccione qué particiones cifrar" msgid "very weak" msgstr "" diff --git a/archinstall/locales/fr/LC_MESSAGES/base.po b/archinstall/locales/fr/LC_MESSAGES/base.po index e58592bf..f5946503 100644 --- a/archinstall/locales/fr/LC_MESSAGES/base.po +++ b/archinstall/locales/fr/LC_MESSAGES/base.po @@ -765,11 +765,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "\"{}\" devrait-il être un superutilisateur (sudo) ?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Sélectionner la partition à marquer comme chiffrée" +msgid "Select which partitions to encrypt" +msgstr "Sélectionner la partition à marquer comme chiffrée" msgid "very weak" msgstr "" diff --git a/archinstall/locales/id/LC_MESSAGES/base.po b/archinstall/locales/id/LC_MESSAGES/base.po index 0ace1b09..85479389 100644 --- a/archinstall/locales/id/LC_MESSAGES/base.po +++ b/archinstall/locales/id/LC_MESSAGES/base.po @@ -763,8 +763,8 @@ msgstr "Nama pengguna yang Anda masukkan tidak valid. Coba lagi" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Haruskah \"{}\" menjadi superuser (sudo)?" -msgid "Select which partitions to encrypt:" -msgstr "Pilih partisi mana yang akan dienkripsi:" +msgid "Select which partitions to encrypt" +msgstr "Pilih partisi mana yang akan dienkripsi" msgid "very weak" msgstr "sangat lemah" diff --git a/archinstall/locales/it/LC_MESSAGES/base.po b/archinstall/locales/it/LC_MESSAGES/base.po index d122b87f..176d3959 100644 --- a/archinstall/locales/it/LC_MESSAGES/base.po +++ b/archinstall/locales/it/LC_MESSAGES/base.po @@ -763,8 +763,8 @@ msgstr "Il nome utente inserito non è valido. Riprova" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "\"{}\" dovrebbe essere un superutente? (sudo)" -msgid "Select which partitions to encrypt:" -msgstr "Seleziona le partizioni da crittografare:" +msgid "Select which partitions to encrypt" +msgstr "Seleziona le partizioni da crittografare" msgid "very weak" msgstr "molto debole" diff --git a/archinstall/locales/ko/LC_MESSAGES/base.mo b/archinstall/locales/ko/LC_MESSAGES/base.mo Binary files differnew file mode 100644 index 00000000..9f86dafd --- /dev/null +++ b/archinstall/locales/ko/LC_MESSAGES/base.mo diff --git a/archinstall/locales/ko/LC_MESSAGES/base.po b/archinstall/locales/ko/LC_MESSAGES/base.po new file mode 100644 index 00000000..b0a85c64 --- /dev/null +++ b/archinstall/locales/ko/LC_MESSAGES/base.po @@ -0,0 +1,838 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: An Jaebeom <ajb8533296@gmail.com>\n" +"Language-Team: \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.1.1\n" + +msgid "[!] A log file has been created here: {} {}" +msgstr "[!] 로그파일을 다음의 경로에 생성했습니다: {} {}" + +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " 이 문제(및 파일)를 https://github.com/archlinux/archinstall/issues 에 제출하세요" + +msgid "Do you really want to abort?" +msgstr "정말 중단하시겠습니까?" + +msgid "And one more time for verification: " +msgstr "확인을 위해 한번 더: " + +msgid "Would you like to use swap on zram?" +msgstr "zram에서 스왑을 사용하시겠습니까?" + +msgid "Desired hostname for the installation: " +msgstr "설치에 원하는 호스트명: " + +msgid "Username for required superuser with sudo privileges: " +msgstr "sudo 권한이 있는 필수 슈퍼유저의 사용자명: " + +msgid "Any additional users to install (leave blank for no users): " +msgstr "설치할 추가 사용자(없는 경우 비워 둠): " + +msgid "Should this user be a superuser (sudoer)?" +msgstr "이 사용자가 슈퍼유저여야 합니까 (sudoer)?" + +msgid "Select a timezone" +msgstr "시간대를 선택하세요" + +msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" +msgstr "systemd-boot 대신 GRUB 를 부트로더로 사용하시겠습니까?" + +msgid "Choose a bootloader" +msgstr "부트로더를 선택하세요" + +msgid "Choose an audio server" +msgstr "오디오 서버를 선택하세요" + +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "base, base-devel, linux, linux-firmware, efibootmgr 및 선택적 프로파일 패키지와 같은 패키지만 설치됩니다." + +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "만약 파이어폭스나 크로미움같은 웹브라우저를 희망하실 경우 다음 프롬프트에서 지정하실 수 있습니다." + +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "설치할 추가 패키지 작성하세요 (띄어쓰기로 구분, 건너뛰려면 공백): " + +msgid "Copy ISO network configuration to installation" +msgstr "ISO 네트워크 구성을 설치에 복사" + +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "NetworkManager 사용 (GNOME 이나 KDE 에서 그래픽으로 인터넷을 구성하는 데 필요)" + +msgid "Select one network interface to configure" +msgstr "구성할 네트워크 인터페이스를 하나 선택하세요" + +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "\"{}\" 에 대해 구성할 모드를 선택하거나 기본 모드 \"{}\" 을(를) 사용하도록 건너뛰세요" + +msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " +msgstr "{} 의 IP와 서브넷을 입력하세요 (예시: 192.168.0.5/24): " + +msgid "Enter your gateway (router) IP address or leave blank for none: " +msgstr "게이트웨이(라우터) IP 주소를 입력하시거나 공백으로 두세요: " + +msgid "Enter your DNS servers (space separated, blank for none): " +msgstr "DNS 서버를 입력하세요 (띄어쓰기로 구분, 없는 경우 공백): " + +msgid "Select which filesystem your main partition should use" +msgstr "주 파티션이 사용해야 하는 파일 시스템을 선택하세요" + +msgid "Current partition layout" +msgstr "현재 파티션 레이아웃" + +msgid "" +"Select what to do with\n" +"{}" +msgstr "" +"무엇을 할 것인지 선택하세요\n" +"{}" + +msgid "Enter a desired filesystem type for the partition" +msgstr "파티션에 대해 원하는 파일 시스템 유형을 입력하세요" + +msgid "Enter the start sector (percentage or block number, default: {}): " +msgstr "시작 섹터를 입력하세요 (백분율 또는 블록 번호, 기본값: {}): " + +msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " +msgstr "파티션의 끝 섹터를 입력하세요 (백분율 또는 블록 번호, 예시: {}): " + +msgid "{} contains queued partitions, this will remove those, are you sure?" +msgstr "{} 에 대기 중인 파티션이 포함되어 있습니다. 그러면 이러한 파티션이 제거됩니다. 정말 진행하시겠습니까?" + +msgid "" +"{}\n" +"\n" +"Select by index which partitions to delete" +msgstr "" +"{}\n" +"\n" +"삭제할 파티션을 인덱스 값으로 선택하세요" + +msgid "" +"{}\n" +"\n" +"Select by index which partition to mount where" +msgstr "" +"{}\n" +"\n" +"마운트할 파티션을 인덱스 값으로 선택하세요" + +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * 파티션 마운트 포인트는 설치 내부를 기준으로 하며 예를 들어 부팅은 /boot 입니다." + +msgid "Select where to mount partition (leave blank to remove mountpoint): " +msgstr "파티션을 마운트할 위치를 선택하세요 (마운트 포인트 제거는 공백): " + +msgid "" +"{}\n" +"\n" +"Select which partition to mask for formatting" +msgstr "" +"{}\n" +"\n" +"포맷을 위해 마스킹할 파티션 선택" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as encrypted" +msgstr "" +"{}\n" +"\n" +"암호화를 위해 마스킹할 파티션 선택" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as bootable" +msgstr "" +"{}\n" +"\n" +"부팅 가능으로 표시할 파티션 선택" + +msgid "" +"{}\n" +"\n" +"Select which partition to set a filesystem on" +msgstr "" +"{}\n" +"\n" +"파일 시스템을 설정할 파티션 선택" + +msgid "Enter a desired filesystem type for the partition: " +msgstr "파티션에 대해 원하는 파일 시스템을 입력하세요: " + +msgid "Archinstall language" +msgstr "Archinstall 언어" + +msgid "Wipe all selected drives and use a best-effort default partition layout" +msgstr "선택한 모든 드라이브를 지우고 최선의 기본 파티션 레이아웃 사용" + +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "각 개별 드라이브로 수행할 작업을 선택하세요 (파티션 사용 후)" + +msgid "Select what you wish to do with the selected block devices" +msgstr "선택한 블록 장치로 수행할 작업을 선택하세요" + +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "이것은 사전 프로그래밍된 프로필 목록이며 데스크톱 환경과 같은 것을 더 쉽게 설치할 수 있습니다" + +msgid "Select keyboard layout" +msgstr "키보드 레이아웃을 선택하세요" + +msgid "Select one of the regions to download packages from" +msgstr "패키지를 다운로드할 지역 중 하나를 선택하세요" + +msgid "Select one or more hard drives to use and configure" +msgstr "사용하고 구성할 하드 드라이브를 하나 이상 선택하세요" + +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "AMD 하드웨어와의 최상의 호환성을 위해 모든 오픈 소스 또는 AMD/ATI 옵션을 사용할 수 있습니다." + +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "인텔 하드웨어와의 최상의 호환성을 위해 모든 오픈 소스 또는 인텔 옵션을 사용할 수 있습니다.\n" + +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Nvidia 하드웨어와의 최상의 호환성을 위해 Nvidia 독점 드라이버를 사용할 수 있습니다.\n" + +msgid "" +"\n" +"\n" +"Select a graphics driver or leave blank to install all open-source drivers" +msgstr "" +"\n" +"\n" +"모든 오픈 소스 드라이버를 설치하려면 그래픽 드라이버를 선택하거나 공백으로 두세요" + +msgid "All open-source (default)" +msgstr "전부 오픈소스 (기본값)" + +msgid "Choose which kernels to use or leave blank for default \"{}\"" +msgstr "사용할 커널을 선택하시거나 기본 커널인 \"{}\" 을(를) 사용하실 경우 비워두세요" + +msgid "Choose which locale language to use" +msgstr "사용할 로케일 언어를 선택하세요" + +msgid "Choose which locale encoding to use" +msgstr "사용할 로케일 인코딩을 선택하세요" + +msgid "Select one of the values shown below: " +msgstr "아래 표시된 값 중 하나를 선택하세요: " + +msgid "Select one or more of the options below: " +msgstr "아래 표시된 값 중 하나 이상을 선택하세요: " + +msgid "Adding partition...." +msgstr "파티션 추가 중...." + +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "계속하려면 유효한 fs-type을 입력해야 합니다. 유효한 fs-type에 대해서는 `man parted`를 참조하세요." + +msgid "Error: Listing profiles on URL \"{}\" resulted in:" +msgstr "오류: URL \"{}\"의 프로필 나열 결과:" + +msgid "Error: Could not decode \"{}\" result as JSON:" +msgstr "오류: \"{}\" 결과를 JSON으로 디코딩할 수 없습니다:" + +msgid "Keyboard layout" +msgstr "키보드 레이아웃" + +msgid "Mirror region" +msgstr "미러 위치" + +msgid "Locale language" +msgstr "로케일 언어" + +msgid "Locale encoding" +msgstr "로케일 인코딩" + +msgid "Drive(s)" +msgstr "드라이브" + +msgid "Disk layout" +msgstr "디스크 레이아웃" + +msgid "Encryption password" +msgstr "비밀번호 암호화" + +msgid "Swap" +msgstr "스왑" + +msgid "Bootloader" +msgstr "부트로더" + +msgid "Root password" +msgstr "루트 비밀번호" + +msgid "Superuser account" +msgstr "슈퍼유저 계정" + +msgid "User account" +msgstr "사용자 계정" + +msgid "Profile" +msgstr "프로필" + +msgid "Audio" +msgstr "오디오" + +msgid "Kernels" +msgstr "커널" + +msgid "Additional packages" +msgstr "추가 패키지" + +msgid "Network configuration" +msgstr "네트워크 구성" + +msgid "Automatic time sync (NTP)" +msgstr "시간 자동 동기화 (NTP)" + +msgid "Install ({} config(s) missing)" +msgstr "설치 ({} 개의 설정(들)이 누락됨)" + +msgid "" +"You decided to skip harddrive selection\n" +"and will use whatever drive-setup is mounted at {} (experimental)\n" +"WARNING: Archinstall won't check the suitability of this setup\n" +"Do you wish to continue?" +msgstr "" +"하드 드라이브 선택을 건너뛰기로 결정했습니다\n" +"{} 에 마운트된 모든 드라이브 설정을 사용합니다 (실험적).\n" +"경고: Archinstall은 이 설정의 적합성을 확인하지 않습니다.\n" +"계속하시겠습니까?" + +msgid "Re-using partition instance: {}" +msgstr "파티션 인스턴스 재사용: {}" + +msgid "Create a new partition" +msgstr "새 파티션 생성" + +msgid "Delete a partition" +msgstr "파티션 제거" + +msgid "Clear/Delete all partitions" +msgstr "모든 파티션 제거" + +msgid "Assign mount-point for a partition" +msgstr "파티션에 대한 마운트 지점 할당" + +msgid "Mark/Unmark a partition to be formatted (wipes data)" +msgstr "포맷할 파티션 표시/표시 해제 (데이터 삭제)" + +msgid "Mark/Unmark a partition as encrypted" +msgstr "암호화된 파티션으로 표시/표시 해제" + +msgid "Mark/Unmark a partition as bootable (automatic for /boot)" +msgstr "부팅 가능한 파티션으로 표시/표시 해제 (/boot의 경우 자동)" + +msgid "Set desired filesystem for a partition" +msgstr "파티션에 대해 원하는 파일 시스템 설정" + +msgid "Abort" +msgstr "중단" + +msgid "Hostname" +msgstr "호스트명" + +msgid "Not configured, unavailable unless setup manually" +msgstr "구성되지 않음, 수동으로 설정하지 않으면 사용할 수 없음" + +msgid "Timezone" +msgstr "시간대" + +msgid "Set/Modify the below options" +msgstr "아래 옵션 설정/수정" + +msgid "Install" +msgstr "설치" + +msgid "" +"Use ESC to skip\n" +"\n" +msgstr "" +"ESC 키를 사용해 스킵하세요\n" +"\n" + +msgid "Suggest partition layout" +msgstr "파티션 레이아웃 제안" + +msgid "Enter a password: " +msgstr "비밀번호를 입력하세요: " + +msgid "Enter a encryption password for {}" +msgstr "{} 에 대한 암호화 비밀번호 입력" + +msgid "Enter disk encryption password (leave blank for no encryption): " +msgstr "디스크를 암호화할 암호를 입력하세요 (암호화하지 않으려면 비워 둠): " + +msgid "Create a required super-user with sudo privileges: " +msgstr "sudo 권한이 있는 필수 슈퍼유저를 생성합니다: " + +msgid "Enter root password (leave blank to disable root): " +msgstr "루트 비밀번호를 입력하세요 (루트를 비활성화 할 경우 공백): " + +msgid "Password for user \"{}\": " +msgstr "사용자 \"{}\" 님에 대한 비밀번호: " + +msgid "Verifying that additional packages exist (this might take a few seconds)" +msgstr "추가 패키지가 있는지 확인합니다 (몇 초 정도 소요될 수 있음)" + +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "기본 시간 서버와 함께 자동 시간 동기화(NTP)를 사용하시겠습니까?\n" + +msgid "" +"Hardware time and other post-configuration steps might be required in order for NTP to work.\n" +"For more information, please check the Arch wiki" +msgstr "" +"NTP가 작동하려면 하드웨어 시간 및 기타 사후 구성 단계가 필요할 수 있습니다.\n" +"더 많은 정보를 확인하시려면, Arch wiki 를 확인하세요" + +msgid "Enter a username to create an additional user (leave blank to skip): " +msgstr "추가 사용자를 만들려면 사용자 이름을 입력하세요 (건너뛰려면 공백): " + +msgid "Use ESC to skip\n" +msgstr "ESC 키를 사용해 스킵하세요\n" + +msgid "" +"\n" +" Choose an object from the list, and select one of the available actions for it to execute" +msgstr "" +"\n" +"목록에서 개체를 선택하고 실행 가능한 작업 중 하나를 선택하세요" + +msgid "Cancel" +msgstr "취소" + +msgid "Confirm and exit" +msgstr "저장 후 종료" + +msgid "Add" +msgstr "추가" + +msgid "Copy" +msgstr "복사" + +msgid "Edit" +msgstr "수정" + +msgid "Delete" +msgstr "제거" + +msgid "Select an action for '{}'" +msgstr "'{}' 에 대한 작업 선택" + +msgid "Copy to new key:" +msgstr "새 키로 복사:" + +msgid "Unknown nic type: {}. Possible values are {}" +msgstr "알 수 없는 nic 타입: {}, 가능한 값은 {} 입니다" + +msgid "" +"\n" +"This is your chosen configuration:" +msgstr "" +"\n" +"선택된 구성:" + +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman 이 이미 실행중입니다, 종료될 때까지 최대 10분 대기해야 합니다." + +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "기존 pacman 잠금이 종료되지 않았습니다. archinstall을 사용하기 전에 기존 pacman 세션을 모두 정리하세요." + +msgid "Choose which optional additional repositories to enable" +msgstr "활성화할 선택적 추가 리포지토리를 선택하세요" + +msgid "Add a user" +msgstr "사용자 추가" + +msgid "Change password" +msgstr "비밀번호 변경" + +msgid "Promote/Demote user" +msgstr "사용자 승격/강등" + +msgid "Delete User" +msgstr "사용자 제거" + +msgid "" +"\n" +"Define a new user\n" +msgstr "" +"\n" +"새 사용자 정의\n" + +msgid "User Name : " +msgstr "사용자명 : " + +msgid "Should {} be a superuser (sudoer)?" +msgstr "{} 님은 슈퍼유저(sudoer)여야 하나요?" + +msgid "Define users with sudo privilege: " +msgstr "sudo 권한이 있는 사용자 정의: " + +msgid "No network configuration" +msgstr "네트워크 구성 없음" + +msgid "Set desired subvolumes on a btrfs partition" +msgstr "btrfs 파티션에 원하는 하위 볼륨 설정" + +msgid "" +"{}\n" +"\n" +"Select which partition to set subvolumes on" +msgstr "" +"{}\n" +"\n" +"하위 볼륨을 설정할 파티션을 선택하세요" + +msgid "Manage btrfs subvolumes for current partition" +msgstr "현재 파티션에 대한 btrfs 하위 볼륨 관리" + +msgid "No configuration" +msgstr "구성 없음" + +msgid "Save user configuration" +msgstr "사용자 구성 저장" + +msgid "Save user credentials" +msgstr "사용자 자격 증명 저장" + +msgid "Save disk layout" +msgstr "디스크 레이아웃 저장" + +msgid "Save all" +msgstr "모두 저장" + +msgid "Choose which configuration to save" +msgstr "저장할 구성을 선택하세요" + +msgid "Enter a directory for the configuration(s) to be saved: " +msgstr "저장할 구성의 디렉토리를 입력하세요: " + +msgid "Not a valid directory: {}" +msgstr "올바른 디렉터리가 아닙니다: {}" + +msgid "The password you are using seems to be weak," +msgstr "사용 중인 비밀번호가 보안에 취약한 것 같습니다," + +msgid "are you sure you want to use it?" +msgstr "그래도 사용하시겠습니까?" + +msgid "Optional repositories" +msgstr "선택적 저장소" + +msgid "Save configuration" +msgstr "구성 저장" + +msgid "Missing configurations:\n" +msgstr "누락된 구성들:\n" + +msgid "Either root-password or at least 1 superuser must be specified" +msgstr "root-password 또는 1명 이상의 슈퍼유저를 지정해야 합니다" + +msgid "Manage superuser accounts: " +msgstr "슈퍼유저 계정 관리: " + +msgid "Manage ordinary user accounts: " +msgstr "일반 사용자 계정 관리: " + +msgid " Subvolume :{:16}" +msgstr " 하위 볼륨 :{:16}" + +msgid " mounted at {:16}" +msgstr " {:16} 에 마운트됨" + +msgid " with option {}" +msgstr " 옵션 {} 와 함께" + +msgid "" +"\n" +" Fill the desired values for a new subvolume \n" +msgstr "" +"\n" +" 새 하위 볼륨에 대해 원하는 값 채우기 \n" + +msgid "Subvolume name " +msgstr "하위 볼륨 이름 " + +msgid "Subvolume mountpoint" +msgstr "하위 볼륨 마운트 지점" + +msgid "Subvolume options" +msgstr "하위 볼륨 옵션" + +msgid "Save" +msgstr "저장" + +msgid "Subvolume name :" +msgstr "하위 볼륨 이름 :" + +msgid "Select a mount point :" +msgstr "마운트 지점을 선택하세요 :" + +msgid "Select the desired subvolume options " +msgstr "원하는 하위 볼륨 옵션을 선택하세요 " + +msgid "Define users with sudo privilege, by username: " +msgstr "sudo 권한을 가질 사용자 이름을 입력하세요: " + +msgid "[!] A log file has been created here: {}" +msgstr "[!] 로그파일이 다음 경로에 생성되었습니다: {}" + +msgid "Would you like to use BTRFS subvolumes with a default structure?" +msgstr "기본 구조로 BTRFS 하위 볼륨을 사용하시겠습니까?" + +msgid "Would you like to use BTRFS compression?" +msgstr "BTRFS 압축을 사용하시겠습니까?" + +msgid "Would you like to create a separate partition for /home?" +msgstr "/home 에 대해 별도의 파티션을 생성하시겠습니까?" + +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "선택한 드라이브에 자동 제안에 필요한 최소 용량이 없습니다\n" + +msgid "Minimum capacity for /home partition: {}GB\n" +msgstr "Arch Linux 파티션의 최대 용량: {}GB\n" + +msgid "Minimum capacity for Arch Linux partition: {}GB" +msgstr "Arch Linux 파티션의 최소 용량: {}GB" + +msgid "Continue" +msgstr "계속" + +msgid "yes" +msgstr "예" + +msgid "no" +msgstr "아니오" + +msgid "set: {}" +msgstr "설정: {}" + +msgid "Manual configuration setting must be a list" +msgstr "수동 구성 설정은 list여야 합니다" + +msgid "No iface specified for manual configuration" +msgstr "수동 구성에 대해 지정된 iface가 없습니다" + +msgid "Manual nic configuration with no auto DHCP requires an IP address" +msgstr "자동 DHCP가 없는 수동 nic 구성에는 IP 주소가 필요합니다" + +msgid "Add interface" +msgstr "인터페이스 추가" + +msgid "Edit interface" +msgstr "인터페이스 수정" + +msgid "Delete interface" +msgstr "인터페이스 제거" + +msgid "Select interface to add" +msgstr "추가할 인터페이스 선택" + +msgid "Manual configuration" +msgstr "수동 구성" + +msgid "Mark/Unmark a partition as compressed (btrfs only)" +msgstr "파티션을 압축된 것으로 표시/표시 해제(btrfs만 해당)" + +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "사용 중인 비밀번호가 보안에 취약한 것 같습니다. 그래도 사용하시겠습니까?" + +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "gnome, kde, sway 같은 다양한 데스크탑 환경 및 타일링 창 관리자를 제공합니다" + +msgid "Select your desired desktop environment" +msgstr "원하는 데스크탑 환경을 선택하세요" + +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Arch Linux를 원하는 대로 커스터마이징할 수 있는 매우 기본적인 설치입니다." + +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "설치 및 활성화할 httpd, nginx, mariadb 같은 다양한 서버 패키지를 제공합니다" + +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "설치할 서버를 선택하고, 설치하지 않으면 최소 설치가 수행됩니다" + +msgid "Installs a minimal system as well as xorg and graphics drivers." +msgstr "최소 시스템과 xorg 및 그래픽 드라이버를 설치합니다." + +msgid "Press Enter to continue." +msgstr "계속하려면 Enter 키를 누르세요." + +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "새로 생성된 설치로 chroot 하고 설치 후 구성을 수행하시겠습니까?" + +msgid "Are you sure you want to reset this setting?" +msgstr "정말 설정을 초기화 하시겠습니까?" + +msgid "Select one or more hard drives to use and configure\n" +msgstr "사용 및 구성할 하드 드라이브를 하나 이상 선택하세요\n" + +msgid "Any modifications to the existing setting will reset the disk layout!" +msgstr "기존 설정을 수정하면 디스크 레이아웃이 재설정됩니다!" + +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "하드 드라이브 선택을 재설정하면 현재 디스크 레이아웃도 재설정됩니다. 정말 진행하시겠습니까?" + +msgid "Save and exit" +msgstr "저장하고 종료" + +msgid "" +"{}\n" +"contains queued partitions, this will remove those, are you sure?" +msgstr "" +"{}\n" +"대기 중인 파티션이 포함되어 있습니다. 그러면 이러한 파티션이 제거됩니다. 정말 진행하시겠습니까?" + +msgid "No audio server" +msgstr "오디오 서버가 없습니다" + +msgid "(default)" +msgstr "(기본)" + +msgid "Use ESC to skip" +msgstr "ESC 키를 사용하여 건너뜁니다" + +msgid "" +"Use CTRL+C to reset current selection\n" +"\n" +msgstr "" +"CTRL+C 를 이용해 현재 선택을 재설정합니다\n" +"\n" + +msgid "Copy to: " +msgstr "다음 경로로 복사: " + +msgid "Edit: " +msgstr "수정됨: " + +msgid "Key: " +msgstr "키: " + +msgid "Edit {}: " +msgstr "수정된 {}: " + +msgid "Add: " +msgstr "추가됨: " + +msgid "Value: " +msgstr "값: " + +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "드라이브 선택 및 파티셔닝을 건너뛰고 /mnt 에 마운트된 드라이브 설정을 사용할 수 있습니다 (실험용)." + +msgid "Select one of the disks or skip and use /mnt as default" +msgstr "디스크 중 하나를 선택하거나 건너뛰고 /mnt 를 기본값으로 사용하세요" + +msgid "Select which partitions to mark for formatting:" +msgstr "포맷할 파티션을 선택하세요:" + +msgid "Use HSM to unlock encrypted drive" +msgstr "HSM을 사용하여 암호화된 드라이브 잠금 해제" + +msgid "Device" +msgstr "장치" + +msgid "Size" +msgstr "크기" + +msgid "Free space" +msgstr "여유 공간" + +msgid "Bus-type" +msgstr "버스 타입" + +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "root-password 또는 sudo 권한이 있는 사용자 1 명 이상을 지정해야 합니다" + +msgid "Enter username (leave blank to skip): " +msgstr "사용자명 입력 (공백일 경우 스킵): " + +msgid "The username you entered is invalid. Try again" +msgstr "입력한 사용자 이름이 잘못되었습니다. 다시 시도하세요" + +msgid "Should \"{}\" be a superuser (sudo)?" +msgstr "\"{}\"은(는) 슈퍼유저여야 합니까 (sudo)?" + +msgid "Select which partitions to encrypt:" +msgstr "암호화할 파티션을 선택하세요:" + +msgid "very weak" +msgstr "아주 약하게" + +msgid "weak" +msgstr "약하게" + +msgid "moderate" +msgstr "보통" + +msgid "strong" +msgstr "강하게" + +msgid "Add subvolume" +msgstr "하위 볼륨 추가" + +msgid "Edit subvolume" +msgstr "하위 볼륨 수정" + +msgid "Delete subvolume" +msgstr "하위 볼륨 제거" + +msgid "Configured {} interfaces" +msgstr "구성된 {} 인터페이스" + +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "이 옵션은 설치 중에 발생할 수 있는 병렬 다운로드 수를 활성화합니다" + +#, python-brace-format +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +" (Enter a value between 1 to {max_downloads})\n" +"Note:" +msgstr "" +"활성화할 병렬 다운로드 수를 입력하세요.\n" +" (1 부터 {max_downloads} 까지의 숫자중 하나를 입력하세요)\n" +"메모:" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - 최댓값 : {max_downloads} ( {max_downloads} 개의 병렬 다운로드 허용, 한 번에 {max_downloads+1} 개의 다운로드 허용 )" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - 최솟값 : 1 ( 1 개의 병렬 다운로드 허용, 한 번에 2 개의 다운로드 허용 )" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr " - 비활성화/기본 : - ( 병렬 다운로드 비활성화, 한 번에 1 개의 다운로드만 허용 )" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "잘못된 값입니다! 유효한 값으로 다시 시도해주세요 [1 부터 {max_downloads} 까지, 비활성화 하려면 0]" + +msgid "Parallel Downloads" +msgstr "병렬 다운로드" + +msgid "ESC to skip" +msgstr "ESC 키로 스킵" + +msgid "CTRL+C to reset" +msgstr "CTRL+C 로 재설정" + +msgid "TAB to select" +msgstr "TAB 으로 선택" + +msgid "[Default value: 0] > " +msgstr "[기본값: 0] > " + +msgid "To be able to use this translation, please install a font manually that supports the language." +msgstr "이 번역을 사용하려면 해당 언어를 지원하는 글꼴을 수동으로 설치하세요." + +msgid "The font should be stored as {}" +msgstr "글꼴은 {} (으)로 저장해야 합니다" diff --git a/archinstall/locales/languages.json b/archinstall/locales/languages.json index 2a7fab2e..495022e8 100644 --- a/archinstall/locales/languages.json +++ b/archinstall/locales/languages.json @@ -86,7 +86,7 @@ {"abbr": "ky", "lang": "Kirghiz"}, {"abbr": "kv", "lang": "Komi"}, {"abbr": "kg", "lang": "Kongo"}, - {"abbr": "ko", "lang": "Korean"}, + {"abbr": "ko", "lang": "Korean", "translated_lang": "한글", "external_dep": true}, {"abbr": "kj", "lang": "Kuanyama"}, {"abbr": "ku", "lang": "Kurdish"}, {"abbr": "lo", "lang": "Lao"}, @@ -128,7 +128,7 @@ {"abbr": "pi", "lang": "Pali"}, {"abbr": "pl", "lang": "Polish", "translated_lang": "Polski"}, {"abbr": "pt", "lang": "Portuguese", "translated_lang": "Português"}, - {"abbr": "pt_BR", "lang": "Brazilian Portuguese", "translated_lang": "Portugues do Brasil"}, + {"abbr": "pt_BR", "lang": "Brazilian Portuguese", "translated_lang": "Português do Brasil"}, {"abbr": "ps", "lang": "Pushto"}, {"abbr": "qu", "lang": "Quechua"}, {"abbr": "rm", "lang": "Romansh"}, @@ -155,7 +155,7 @@ {"abbr": "sw", "lang": "Swahili (macrolanguage)"}, {"abbr": "sv", "lang": "Swedish", "translated_lang": "Svenska"}, {"abbr": "ty", "lang": "Tahitian"}, - {"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்", "external_dep": true}, + {"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்"}, {"abbr": "tt", "lang": "Tatar"}, {"abbr": "te", "lang": "Telugu"}, {"abbr": "tg", "lang": "Tajik"}, @@ -170,7 +170,7 @@ {"abbr": "tw", "lang": "Twi"}, {"abbr": "ug", "lang": "Uighur"}, {"abbr": "uk", "lang": "Ukrainian"}, - {"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو", "external_dep": true}, + {"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو"}, {"abbr": "uz", "lang": "Uzbek"}, {"abbr": "ve", "lang": "Venda"}, {"abbr": "vi", "lang": "Vietnamese"}, diff --git a/archinstall/locales/nl/LC_MESSAGES/base.po b/archinstall/locales/nl/LC_MESSAGES/base.po index 4eb93e22..b7323059 100644 --- a/archinstall/locales/nl/LC_MESSAGES/base.po +++ b/archinstall/locales/nl/LC_MESSAGES/base.po @@ -791,11 +791,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Moet {} gebruiker een beheerder (sudoer) worden?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Kies welke partitie moet worden versleuteld" +msgid "Select which partitions to encrypt" +msgstr "Kies welke partitie moet worden versleuteld" msgid "very weak" msgstr "" diff --git a/archinstall/locales/pl/LC_MESSAGES/base.mo b/archinstall/locales/pl/LC_MESSAGES/base.mo Binary files differindex e9051d78..0e8e7bef 100644 --- a/archinstall/locales/pl/LC_MESSAGES/base.mo +++ b/archinstall/locales/pl/LC_MESSAGES/base.mo diff --git a/archinstall/locales/pl/LC_MESSAGES/base.po b/archinstall/locales/pl/LC_MESSAGES/base.po index d1c50634..6655bbbd 100644 --- a/archinstall/locales/pl/LC_MESSAGES/base.po +++ b/archinstall/locales/pl/LC_MESSAGES/base.po @@ -6,6 +6,10 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"X-Generator: Poedit 2.4.2\n" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Plik dziennika został stworzony tutaj: {} {}" @@ -26,13 +30,13 @@ msgid "Desired hostname for the installation: " msgstr "Nazwa hosta użyta do instalacji: " msgid "Username for required superuser with sudo privileges: " -msgstr "Nazwa użytkownika dla wymaganego superużytkownika z uprawnieniami sudo: " +msgstr "Nazwa użytkownika dla wymaganego superusera z uprawnieniami sudo: " msgid "Any additional users to install (leave blank for no users): " msgstr "Ewentualni użytkownicy do instalacji (pozostaw puste jeśli nie chcesz tworzyć użytkowników): " msgid "Should this user be a superuser (sudoer)?" -msgstr "Czy użytkownik powinien być superużytkownikiem (sudoer)?" +msgstr "Czy użytkownik powinien być superuserem (sudo)?" msgid "Select a timezone" msgstr "Wybierz strefę czasową" @@ -251,26 +255,23 @@ msgstr "Locale kodowania" msgid "Drive(s)" msgstr "Dyski twarde" -#, fuzzy msgid "Disk layout" -msgstr "Zapisz układ dysku" +msgstr "Układ dysku" -#, fuzzy msgid "Encryption password" -msgstr "Ustaw hasło szyfrowania" +msgstr "Hasło szyfrujące" msgid "Swap" -msgstr "Swap" +msgstr "Pamięć wymiany (swap)" msgid "Bootloader" msgstr "Program rozruchowy" -#, fuzzy msgid "Root password" -msgstr "Hasło root" +msgstr "Hasło użytkownika root" msgid "Superuser account" -msgstr "Konto superużytkownika" +msgstr "Konto superusera" msgid "User account" msgstr "Konto użytkownika" @@ -294,7 +295,7 @@ msgid "Automatic time sync (NTP)" msgstr "Automatycznej synchronizacji czasu (NTP)" msgid "Install ({} config(s) missing)" -msgstr "Zainstaluj ({} brakuje konfiguracji)" +msgstr "Zainstaluj ({} brakujących konfiguracji)" msgid "" "You decided to skip harddrive selection\n" @@ -303,18 +304,18 @@ msgid "" "Do you wish to continue?" msgstr "" "Zdecydowałeś się pominąć wybór dysku twardego\n" -"i użyje konfiguracji dysku zamontowanego w {} (eksperymentalne)\n" -"OSTRZEŻENIE: Archinstall nie sprawdzi przydatności tej konfiguracji\n" +"i użyć konfiguracji dysku zamontowanego w {} (eksperymentalne)\n" +"OSTRZEŻENIE: Archinstall nie sprawdzi poprawności tej konfiguracji\n" "Czy chcesz kontynuować?" msgid "Re-using partition instance: {}" -msgstr "Ponowne wykorzystanie instancji partycji" +msgstr "Ponowne wykorzystanie instancji partycji: {}" msgid "Create a new partition" msgstr "Utwórz nową partycję" msgid "Delete a partition" -msgstr "Usuń partycje" +msgstr "Usuń partycję" msgid "Clear/Delete all partitions" msgstr "Wyczyść/Usuń wszystkie partycje" @@ -338,13 +339,13 @@ msgid "Abort" msgstr "Anuluj" msgid "Hostname" -msgstr "Nazwę hosta" +msgstr "Nazwa hosta" msgid "Not configured, unavailable unless setup manually" -msgstr "Nie skonfigurowana, niedostępna, chyba że zostanie skonfigurowana ręcznie" +msgstr "Niedostępna, chyba że zostanie skonfigurowana ręcznie" msgid "Timezone" -msgstr "Strefe czasową" +msgstr "Strefa czasowa" msgid "Set/Modify the below options" msgstr "Ustaw/zmodyfikuj poniższe opcje" @@ -372,13 +373,13 @@ msgid "Enter disk encryption password (leave blank for no encryption): " msgstr "Wprowadź hasło do szyfrowania dysku (pozostaw puste aby nie ustawiać szyfrowania): " msgid "Create a required super-user with sudo privileges: " -msgstr "Utwórz wymaganego superużytkownika z uprawnieniami sudo: " +msgstr "Utwórz wymaganego superusera z uprawnieniami sudo: " msgid "Enter root password (leave blank to disable root): " msgstr "Wprowadź hasło roota (pozostaw puste, aby wyłączyć roota): " msgid "Password for user \"{}\": " -msgstr "Hasło dla użytkownika \"{}\": " +msgstr "Hasło użytkownika \"{}\": " msgid "Verifying that additional packages exist (this might take a few seconds)" msgstr "Sprawdzenie, czy istnieją dodatkowe pakiety (może to potrwać kilka sekund)" @@ -438,7 +439,7 @@ msgid "" "This is your chosen configuration:" msgstr "" "\n" -"To jest wybrana konfiguracja:" +"Wybrana konfiguracja:" msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." msgstr "Pacman jest już uruchomiony i czeka maksymalnie 10 minut na zakończenie pracy." @@ -449,7 +450,6 @@ msgstr "Istniejąca wcześniej blokada programu pacman nie została zakończona. msgid "Choose which optional additional repositories to enable" msgstr "Wybierz, które z opcjonalnych dodatkowych repozytoriów mają być włączone" -#, fuzzy msgid "Add a user" msgstr "Dodaj użytkownika" @@ -533,10 +533,10 @@ msgid "Missing configurations:\n" msgstr "Brak konfiguracji:\n" msgid "Either root-password or at least 1 superuser must be specified" -msgstr "Musi być podane albo hasło root, albo co najmniej jednego superużytkownika" +msgstr "Musi być podane albo hasło root, albo co najmniej jednego superusera" msgid "Manage superuser accounts: " -msgstr "Zarządzaj kontami superużytkowników: " +msgstr "Zarządzaj kontami superusera: " msgid "Manage ordinary user accounts: " msgstr "Zarządzaj kontami zwykłych użytkowników: " @@ -594,13 +594,13 @@ msgid "Would you like to create a separate partition for /home?" msgstr "Czy chcesz stworzyć oddzielną partycje dla /home?" msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" -msgstr "Wybrane dyski nie mają wymaganej objętości dla automatycznej sugestii\n" +msgstr "Wybrane dyski nie mają wymaganej pojemności dla automatycznej sugestii\n" msgid "Minimum capacity for /home partition: {}GB\n" -msgstr "Maksymalna objętość dla partycji /home: {}GB\n" +msgstr "Maksymalna pojemność dla partycji /home: {}GB\n" msgid "Minimum capacity for Arch Linux partition: {}GB" -msgstr "Minimalna objętośc dla partycji Arch Linux: {}GB" +msgstr "Minimalna pojemność dla partycji Arch Linux: {}GB" msgid "Continue" msgstr "Kontynuuj" @@ -618,10 +618,10 @@ msgid "Manual configuration setting must be a list" msgstr "Konfiguracja ustawiona manualnie musi być listą" msgid "No iface specified for manual configuration" -msgstr "Iface nie zostało ustawione w manualnej konfiguracji" +msgstr "Iface nie zostało ustawione w ręcznej konfiguracji" msgid "Manual nic configuration with no auto DHCP requires an IP address" -msgstr "" +msgstr "Ręczna konfiguracja nic bez automatycznego DHCP wymaga podania adresu IP" msgid "Add interface" msgstr "Dodaj interfejs" @@ -629,17 +629,14 @@ msgstr "Dodaj interfejs" msgid "Edit interface" msgstr "Edytuj interfejs" -#, fuzzy msgid "Delete interface" msgstr "Usuń interfejs" -#, fuzzy msgid "Select interface to add" -msgstr "Wybierz jeden interfejs sieciowy do skonfigurowania" +msgstr "Wybierz interfejs sieciowy do skonfigurowania" -#, fuzzy msgid "Manual configuration" -msgstr "Zapisz konfiguracje" +msgstr "Ręczna konfiguracja" msgid "Mark/Unmark a partition as compressed (btrfs only)" msgstr "Oznacz/odznacz partycje jako skompresowaną (tylko w btrfs)" @@ -648,43 +645,41 @@ msgid "The password you are using seems to be weak, are you sure you want to use msgstr "Używane przez Ciebie hasło wydaje się być słabe, czy na pewno chcesz go użyć?" msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" -msgstr "Dostarcza wybór środowisk desktopowych oraz tiling window managerów, np. gnome, kde, sway" +msgstr "Dostarcza wybór środowisk graficznych oraz menedżerów okien, np. gnome, kde, sway" msgid "Select your desired desktop environment" -msgstr "Wybierz pożądane środowisko desktopowe" +msgstr "Wybierz środowisko graficzne" msgid "A very basic installation that allows you to customize Arch Linux as you see fit." -msgstr "Bardzo podstawowa instalacja pozwalająca ci dostosowanie Arch Linuxa do twoich upodobań." +msgstr "Bardzo ograniczona instalacja pozwalająca ci dostosowanie Arch Linuxa do twoich upodobań." msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Dostarcza wybór różnych pakietów serwerowych do zainstalowania i uruchomienia, np. httpd, nginx, mariadb" -#, fuzzy msgid "Choose which servers to install, if none then a minimal installation will be done" -msgstr "Wybierz jakie serwery zainstalować, jeżeli żadne, wtedy minimalna instalacja będzie użyta" +msgstr "Wybierz jakie serwery zainstalować. Jeżeli żadne, wtedy będzie użyta minimalna instalacja" msgid "Installs a minimal system as well as xorg and graphics drivers." -msgstr "Instaluje minimalną wersje systemu z xorg i sterownikami graficznymi." +msgstr "Instaluje system podstawowy z xorg i sterownikami graficznymi." msgid "Press Enter to continue." -msgstr "Naciśnij Enter aby kontynuować." +msgstr "Naciśnij Enter, aby kontynuować." msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" -msgstr "Czy chciałbyś zchrootować do nowostworzonej instalacji i przeprowadzić po-instalacyjną konfiguracje?" +msgstr "Czy chciałbyś zchrootować do nowej instalacji i przeprowadzić wstępną konfigurację?" msgid "Are you sure you want to reset this setting?" -msgstr "Czy napewno chcesz zresetować to ustawienie?" +msgstr "Czy na pewno chcesz zresetować to ustawienie?" msgid "Select one or more hard drives to use and configure\n" msgstr "Wybierz jeden lub więcej dysków twardych do użycia i skonfiguruj je\n" msgid "Any modifications to the existing setting will reset the disk layout!" -msgstr "Jakiekolwiek modyfikacje do istniejących ustawień zresetują układ dysków!" +msgstr "Każda zmiana istniejących ustawień zresetuje układ dysków!" msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" -msgstr "Jeżeli zresetujesz wybór dysków, zresetujesz także obecny układ dysków. Jesteś pewny że chcesz to zrobić?" +msgstr "Jeżeli zresetujesz wybór dysków, zresetujesz także obecny układ dysków. Jesteś pewny, że chcesz to zrobić?" -#, fuzzy msgid "Save and exit" msgstr "Zapisz i wyjdź" @@ -700,17 +695,16 @@ msgid "No audio server" msgstr "Brak serwera dźwięku" msgid "(default)" -msgstr "(domyslne)" +msgstr "(domyślne)" -#, fuzzy msgid "Use ESC to skip" -msgstr "Kliknij ESC aby pominąć" +msgstr "Naciśnij ESC, aby pominąć" msgid "" "Use CTRL+C to reset current selection\n" "\n" msgstr "" -"Użyj CTRL+C aby zresetować obecny wybór\n" +"Użyj CTRL+C, aby zresetować obecny wybór\n" "\n" msgid "Copy to: " @@ -729,18 +723,18 @@ msgstr "Edytuj {}: " msgid "Add: " msgstr "Dodaj: " -#, fuzzy msgid "Value: " msgstr "Wartość: " +#, fuzzy msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" -msgstr "Możesz pominąć wybów dysków i partycji i użyć dowolnego zestawu dysku zamontowanego w /mnt (eksperymentalne)" +msgstr "Możesz pominąć wybór dysków i partycji i użyć dowolnego zestawu dysku zamontowanego w /mnt (eksperymentalne)" msgid "Select one of the disks or skip and use /mnt as default" msgstr "Wybierz jeden z dysków lub pomiń i użyj /mnt jako domyślnego" msgid "Select which partitions to mark for formatting:" -msgstr "Wybierz partycja która ma zostać sformatowana:" +msgstr "Wybierz partycje, które mają zostać sformatowane:" msgid "Use HSM to unlock encrypted drive" msgstr "Użyj HSM do odblokowania zaszyfrowanego dysku" @@ -757,27 +751,21 @@ msgstr "Wolne miejsce" msgid "Bus-type" msgstr "Typ magistrali" -#, fuzzy msgid "Either root-password or at least 1 user with sudo privileges must be specified" -msgstr "Musi być podane albo hasło root, albo co najmniej jednego superużytkownika" +msgstr "Musisz podać hasło root lub utworzyć co najmniej jednego superusera" -#, fuzzy msgid "Enter username (leave blank to skip): " -msgstr "Wprowadź nazwę użytkownika, aby utworzyć dodatkowego użytkownika (pozostaw puste, aby pominąć): " +msgstr "Wprowadź nazwę użytkownika (pozostaw puste, aby pominąć): " msgid "The username you entered is invalid. Try again" msgstr "Wprowadzona nazwa użytkownika jest nieprawidłowa. Spróbuj ponownie" -#, fuzzy msgid "Should \"{}\" be a superuser (sudo)?" -msgstr "Czy {} powinien być superuserem (sudoer)?" +msgstr "Czy \"{}\" powinien być superuserem (sudo)?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Wybierz partycja która ma zostać zaszyfrowana" +msgid "Select which partitions to encrypt" +msgstr "Wybierz partycja która ma zostać zaszyfrowana" msgid "very weak" msgstr "bardzo słabe" @@ -791,55 +779,56 @@ msgstr "umiarkowane" msgid "strong" msgstr "mocne" -#, fuzzy msgid "Add subvolume" -msgstr "Subwolumin :{:16}" +msgstr "Dodaj podwolumen" msgid "Edit subvolume" -msgstr "Edytuj wolumen" +msgstr "Edytuj podwolumen" -#, fuzzy msgid "Delete subvolume" -msgstr "Usuń użytkownika" +msgstr "Usuń podwolumen" msgid "Configured {} interfaces" -msgstr "" +msgstr "Skonfigurowano {} interfejsów" msgid "This option enables the number of parallel downloads that can occur during installation" -msgstr "" +msgstr "Ta opcja pozwala określić maksymalną liczbę pobieranych plików podczas instalacji" -#, python-brace-format +#, fuzzy, python-brace-format msgid "" "Enter the number of parallel downloads to be enabled.\n" " (Enter a value between 1 to {max_downloads})\n" "Note:" msgstr "" +"Wprowadź maksymalną liczbę plików pobieranych jednocześnie.\n" +" (Liczba z zakresu od 1 do {max_downloads})\n" +"Zauważ:" msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" -msgstr "" +msgstr " - Maksymalna wartość : {max_downloads} ( Zwiększa liczbę zadań o {max_downloads}, co pozwala na pobieranie {max_downloads+1} plików jednocześnie )" msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" -msgstr "" +msgstr " - Minimalna wartość : 1 ( Zwiększa liczbę zadań o 1, co pozwala na pobieranie 2 plików jednocześnie )" msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" -msgstr "" +msgstr " - Wyłącz/domyślnie : 0 ( Wyłącza pobieranie równoległe, więc tylko 1 plik może być pobierany w tym czasie )" -#, python-brace-format +#, fuzzy, python-brace-format msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" -msgstr "" +msgstr "Nieprawidłowa wartość! Spróbuj wprowadzić wartość od 1 do {max_downloads}, lub 0 aby wyłączyć." msgid "Parallel Downloads" -msgstr "" +msgstr "Pobieranie równoległe" -#, fuzzy msgid "ESC to skip" -msgstr "Kliknij ESC aby pominąć" +msgstr "Naciśnij ESC, aby pominąć" msgid "CTRL+C to reset" -msgstr "" +msgstr "Naciśnij Ctrl+C, aby zresetować" +#, fuzzy msgid "TAB to select" -msgstr "" +msgstr "Naciśnij Tab, aby wybrać" #~ msgid "Select disk layout" #~ msgstr "Wybierz układ dysku" diff --git a/archinstall/locales/pt/LC_MESSAGES/base.po b/archinstall/locales/pt/LC_MESSAGES/base.po index 55569546..683de0ad 100644 --- a/archinstall/locales/pt/LC_MESSAGES/base.po +++ b/archinstall/locales/pt/LC_MESSAGES/base.po @@ -811,11 +811,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Deve {} ser um superutilizador (sudoer)?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Seleciona a partição a marcar como encriptada" +msgid "Select which partitions to encrypt" +msgstr "Seleciona a partição a marcar como encriptada" msgid "very weak" msgstr "" diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.mo b/archinstall/locales/pt_BR/LC_MESSAGES/base.mo Binary files differindex c66bae7f..931e0ddf 100644 --- a/archinstall/locales/pt_BR/LC_MESSAGES/base.mo +++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.mo diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.po b/archinstall/locales/pt_BR/LC_MESSAGES/base.po index 73a25b19..938f5068 100644 --- a/archinstall/locales/pt_BR/LC_MESSAGES/base.po +++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.po @@ -761,8 +761,8 @@ msgstr "O nome de usuário que você digitou é inválido. Tente novamente" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "\"{}\" deve ser um superusuário (sudo)?" -msgid "Select which partitions to encrypt:" -msgstr "Selecione quais partições encriptar:" +msgid "Select which partitions to encrypt" +msgstr "Selecione quais partições encriptar" msgid "very weak" msgstr "muito fraca" @@ -789,7 +789,7 @@ msgid "Configured {} interfaces" msgstr "{} interfaces configuradas" msgid "This option enables the number of parallel downloads that can occur during installation" -msgstr "" +msgstr "Esta opção habilita o número de downloads paralelos que podem ocorrer durante a instalação" #, python-brace-format msgid "" @@ -797,29 +797,41 @@ msgid "" " (Enter a value between 1 to {max_downloads})\n" "Note:" msgstr "" +"Insira o número de downloads paralelos para serem habilitados.\n" +" (Insira um valor entre 1 e {max_downloads})\n" +"Observação:" msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" -msgstr "" +msgstr " - Valor máximo : {max_downloads} ( Permite {max_donwloads} downloads paralelos, permite {max_donwloads+1} downloads por vez )" msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" -msgstr "" +msgstr " - Valor minimo : 1 ( Permite 1 download paralelo, permite 2 downloads por vez )" msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" -msgstr "" +msgstr " - Desativar/Padrão : 0 ( Desativa os downloads paralelos, permite apenas 1 download por vez )" #, python-brace-format msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" -msgstr "" +msgstr "Entrada inválida! Tente novamente com uma entrada válida [1 para {max_downloads}, ou 0 para desativar]" msgid "Parallel Downloads" -msgstr "" +msgstr "Downloads Paralelos" #, fuzzy msgid "ESC to skip" msgstr "Use ESC para pular" msgid "CTRL+C to reset" -msgstr "" +msgstr "CTRL+C para reiniciar" msgid "TAB to select" -msgstr "" +msgstr "TAB para selecionar" + +msgid "[Default value: 0] > " +msgstr "[Valor padrão: 0] > " + +msgid "To be able to use this translation, please install a font manually that supports the language." +msgstr "Para poder usar esta tradução, instale manualmente uma fonte que suporte o idioma." + +msgid "The font should be stored as {}" +msgstr "A fonte deve ser armazenada como {}" diff --git a/archinstall/locales/ru/LC_MESSAGES/base.po b/archinstall/locales/ru/LC_MESSAGES/base.po index 6d5799eb..a62a8385 100644 --- a/archinstall/locales/ru/LC_MESSAGES/base.po +++ b/archinstall/locales/ru/LC_MESSAGES/base.po @@ -764,8 +764,8 @@ msgstr "Введенное вами имя пользователя недейс msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Должен ли \"{}\" быть суперпользователем (sudo)?" -msgid "Select which partitions to encrypt:" -msgstr "Выберите разделы для шифрования:" +msgid "Select which partitions to encrypt" +msgstr "Выберите разделы для шифрования" msgid "very weak" msgstr "очень слабый" diff --git a/archinstall/locales/sv/LC_MESSAGES/base.po b/archinstall/locales/sv/LC_MESSAGES/base.po index 9d7f7455..fc311551 100644 --- a/archinstall/locales/sv/LC_MESSAGES/base.po +++ b/archinstall/locales/sv/LC_MESSAGES/base.po @@ -772,11 +772,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "Är detta en superanvändare (sudo-rättigheter)?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Välj vilken partition som skall markeras för kryptering" +msgid "Select which partitions to encrypt" +msgstr "Välj vilken partition som skall markeras för kryptering" msgid "very weak" msgstr "" diff --git a/archinstall/locales/ta/LC_MESSAGES/base.po b/archinstall/locales/ta/LC_MESSAGES/base.po index 3ea3dd19..4375f477 100644 --- a/archinstall/locales/ta/LC_MESSAGES/base.po +++ b/archinstall/locales/ta/LC_MESSAGES/base.po @@ -763,8 +763,8 @@ msgstr "நீங்கள் உள்ளிட்ட பயனர்பெய msgid "Should \"{}\" be a superuser (sudo)?" msgstr "\"{}\" ஒரு சூப்பர் யூசராக (sudo) இருக்க வேண்டுமா?" -msgid "Select which partitions to encrypt:" -msgstr "குறியாக்கம் செய்ய வேண்டிய பகிர்வுகளைத் தேர்ந்தெடுக்கவும்:" +msgid "Select which partitions to encrypt" +msgstr "குறியாக்கம் செய்ய வேண்டிய பகிர்வுகளைத் தேர்ந்தெடுக்கவும்" msgid "very weak" msgstr "மிகவும் பலவீனமானது" diff --git a/archinstall/locales/tr/LC_MESSAGES/base.po b/archinstall/locales/tr/LC_MESSAGES/base.po index c38f467e..fd1e2393 100644 --- a/archinstall/locales/tr/LC_MESSAGES/base.po +++ b/archinstall/locales/tr/LC_MESSAGES/base.po @@ -772,11 +772,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "{} bir süper kullanıcı (sudoer) olmalı mı?" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"Hangi disk bölümünün şifrelenmiş olarak işaretleneceğini seçin" +msgid "Select which partitions to encrypt" +msgstr "Hangi disk bölümünün şifrelenmiş olarak işaretleneceğini seçin" msgid "very weak" msgstr "" diff --git a/archinstall/locales/ur/LC_MESSAGES/base.po b/archinstall/locales/ur/LC_MESSAGES/base.po index 8ab6c4e2..0b024031 100644 --- a/archinstall/locales/ur/LC_MESSAGES/base.po +++ b/archinstall/locales/ur/LC_MESSAGES/base.po @@ -794,11 +794,8 @@ msgid "Should \"{}\" be a superuser (sudo)?" msgstr "کیا {} کو سپر یوزر (sudoer) ہونا چاہیے؟" #, fuzzy -msgid "Select which partitions to encrypt:" -msgstr "" -"{}\n" -"\n" -"منتخب کریں کہ کس پارٹیشن کو انکرپٹڈ یا خفیہ رکھنا ہے" +msgid "Select which partitions to encrypt" +msgstr "منتخب کریں کہ کس پارٹیشن کو انکرپٹڈ یا خفیہ رکھنا ہے" msgid "very weak" msgstr "" diff --git a/archinstall/locales/zh-CN/LC_MESSAGES/base.mo b/archinstall/locales/zh-CN/LC_MESSAGES/base.mo Binary files differnew file mode 100644 index 00000000..70cb4064 --- /dev/null +++ b/archinstall/locales/zh-CN/LC_MESSAGES/base.mo diff --git a/archinstall/locales/zh-CN/LC_MESSAGES/base.po b/archinstall/locales/zh-CN/LC_MESSAGES/base.po new file mode 100644 index 00000000..60f88a01 --- /dev/null +++ b/archinstall/locales/zh-CN/LC_MESSAGES/base.po @@ -0,0 +1,836 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Xiaotian Wu <yetist@gmail.com>\n" +"Language-Team: \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.1.1\n" + +msgid "[!] A log file has been created here: {} {}" +msgstr "[!] 已在此处创建日志文件:{} {}" + +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " 请将此问题(和文件)提交到 https://github.com/archlinux/archinstall/issues" + +msgid "Do you really want to abort?" +msgstr "你真的想中止吗?" + +msgid "And one more time for verification: " +msgstr "还有一次验证: " + +msgid "Would you like to use swap on zram?" +msgstr "你想在 zram 上使用交换吗?" + +msgid "Desired hostname for the installation: " +msgstr "安装所需的主机名: " + +msgid "Username for required superuser with sudo privileges: " +msgstr "具有 sudo 权限的所需超级用户的用户名: " + +msgid "Any additional users to install (leave blank for no users): " +msgstr "要新建的任何其他用户(留空表示没有用户): " + +msgid "Should this user be a superuser (sudoer)?" +msgstr "这个用户应该是超级用户(sudoer)吗?" + +msgid "Select a timezone" +msgstr "选择时区" + +msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" +msgstr "您想使用 GRUB 作为引导加载程序而不是 systemd-boot 吗?" + +msgid "Choose a bootloader" +msgstr "选择引导加载程序" + +msgid "Choose an audio server" +msgstr "选择音频服务器" + +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "仅安装 base、base-devel、linux、linux-firmware、efibootmgr 和可选配置文件包等软件包。" + +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "如果你想要一个 web 浏览器,例如 firefox 或 chromium,你可以在下面的提示中指定它。" + +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "编写要安装的附加软件包(空格分隔,留空跳过): " + +msgid "Copy ISO network configuration to installation" +msgstr "将 ISO 网络配置复制到安装" + +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "使用 NetworkManager(在 GNOME 和 KDE 中以图形方式配置 Internet 所必需的)" + +msgid "Select one network interface to configure" +msgstr "选择一个网络接口进行配置" + +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "选择要为“{}”配置的模式或跳过以使用默认模式“{}”" + +msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " +msgstr "输入 {} 的 IP 和子网(例如:192.168.0.5/24): " + +msgid "Enter your gateway (router) IP address or leave blank for none: " +msgstr "输入您的网关(路由器)IP 地址或留空为无: " + +msgid "Enter your DNS servers (space separated, blank for none): " +msgstr "输入您的 DNS 服务器(空格分隔,空白表示无): " + +msgid "Select which filesystem your main partition should use" +msgstr "选择你的主分区应该使用哪个文件系统" + +msgid "Current partition layout" +msgstr "当前分区布局" + +msgid "" +"Select what to do with\n" +"{}" +msgstr "" +"选择要做什么\n" +"{}" + +msgid "Enter a desired filesystem type for the partition" +msgstr "为分区输入所需的文件系统类型" + +msgid "Enter the start sector (percentage or block number, default: {}): " +msgstr "输入起始扇区(百分比或块号,默认:{}): " + +msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " +msgstr "输入分区的结束扇区(百分比或块号,例如:{}): " + +msgid "{} contains queued partitions, this will remove those, are you sure?" +msgstr "{} 包含排队分区,这将删除这些分区,您确定吗?" + +msgid "" +"{}\n" +"\n" +"Select by index which partitions to delete" +msgstr "" +"{}\n" +"\n" +"按索引选择要删除的分区" + +msgid "" +"{}\n" +"\n" +"Select by index which partition to mount where" +msgstr "" +"{}\n" +"\n" +"按索引选择要挂载的分区" + +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * 分区挂载点是相对于安装内部的,例如 boot 应该为 /boot。" + +msgid "Select where to mount partition (leave blank to remove mountpoint): " +msgstr "选择挂载分区的位置(留空以删除挂载点): " + +msgid "" +"{}\n" +"\n" +"Select which partition to mask for formatting" +msgstr "" +"{}\n" +"\n" +"选择要标记的分区以进行格式化" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as encrypted" +msgstr "" +"{}\n" +"\n" +"选择要标记为加密的分区" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as bootable" +msgstr "" +"{}\n" +"\n" +"选择要标记为可引导的分区" + +msgid "" +"{}\n" +"\n" +"Select which partition to set a filesystem on" +msgstr "" +"{}\n" +"\n" +"选择要在哪个分区上设置文件系统" + +msgid "Enter a desired filesystem type for the partition: " +msgstr "为分区输入所需的文件系统类型: " + +msgid "Archinstall language" +msgstr "Archinstall 界面语言" + +msgid "Wipe all selected drives and use a best-effort default partition layout" +msgstr "擦除所有选定的驱动器并使用最优的默认分区布局" + +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "选择如何处理每个单独的驱动器(其次是分区使用情况)" + +msgid "Select what you wish to do with the selected block devices" +msgstr "选择您希望对所选块设备执行的操作" + +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "这是预编程配置文件的列表,它们可能使安装桌面环境之类的东西变得更容易" + +msgid "Select keyboard layout" +msgstr "选择键盘布局" + +msgid "Select one of the regions to download packages from" +msgstr "选择要从中下载软件包的区域之一" + +msgid "Select one or more hard drives to use and configure" +msgstr "选择一个或多个硬盘驱动器来使用和配置" + +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "为了与您的 AMD 硬件实现最佳兼容性,您可能需要使用所有开源或 AMD / ATI 选项。" + +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "为了与您的 Intel 硬件实现最佳兼容性,您可能需要使用所有开源或 Intel 选项。\n" + +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "为了与您的 Nvidia 硬件实现最佳兼容性,您可能需要使用 Nvidia 专有驱动程序。\n" + +msgid "" +"\n" +"\n" +"Select a graphics driver or leave blank to install all open-source drivers" +msgstr "" +"\n" +"\n" +"选择图形驱动程序或留空以安装所有开源驱动程序" + +msgid "All open-source (default)" +msgstr "全部开源(默认)" + +msgid "Choose which kernels to use or leave blank for default \"{}\"" +msgstr "选择要使用的内核或将默认“{}”留空" + +msgid "Choose which locale language to use" +msgstr "选择要使用的语言环境" + +msgid "Choose which locale encoding to use" +msgstr "选择要使用的语言环境编码" + +msgid "Select one of the values shown below: " +msgstr "选择如下所示的值之一: " + +msgid "Select one or more of the options below: " +msgstr "选择以下一个或多个选项: " + +msgid "Adding partition...." +msgstr "添加分区...." + +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "您需要输入有效的文件系统类型才能继续。有关有效的文件系统类型,请参阅 `man parted`。" + +msgid "Error: Listing profiles on URL \"{}\" resulted in:" +msgstr "错误:在 URL“{}”上列出配置文件导致:" + +msgid "Error: Could not decode \"{}\" result as JSON:" +msgstr "错误:无法将“{}”结果解码为 JSON:" + +msgid "Keyboard layout" +msgstr "键盘布局" + +msgid "Mirror region" +msgstr "镜像区域" + +msgid "Locale language" +msgstr "本地语言" + +msgid "Locale encoding" +msgstr "本地编码" + +msgid "Drive(s)" +msgstr "驱动器" + +msgid "Disk layout" +msgstr "磁盘布局" + +msgid "Encryption password" +msgstr "加密密码" + +msgid "Swap" +msgstr "交换分区" + +msgid "Bootloader" +msgstr "引导加载程序" + +msgid "Root password" +msgstr "Root 密码" + +msgid "Superuser account" +msgstr "超级用户帐户" + +msgid "User account" +msgstr "用户帐户" + +msgid "Profile" +msgstr "配置文件" + +msgid "Audio" +msgstr "音频" + +msgid "Kernels" +msgstr "内核" + +msgid "Additional packages" +msgstr "附加包" + +msgid "Network configuration" +msgstr "网络配置" + +msgid "Automatic time sync (NTP)" +msgstr "自动时间同步 (NTP)" + +msgid "Install ({} config(s) missing)" +msgstr "安装(缺少 {} 个配置)" + +msgid "" +"You decided to skip harddrive selection\n" +"and will use whatever drive-setup is mounted at {} (experimental)\n" +"WARNING: Archinstall won't check the suitability of this setup\n" +"Do you wish to continue?" +msgstr "" +"你决定跳过硬盘选择\n" +"并将使用安装在 {} 上的任何驱动器设置(实验性)\n" +"警告:Archinstall 不会检查此设置的适用性\n" +"你想继续吗?" + +msgid "Re-using partition instance: {}" +msgstr "重用分区实例:{}" + +msgid "Create a new partition" +msgstr "创建新分区" + +msgid "Delete a partition" +msgstr "删除一个分区" + +msgid "Clear/Delete all partitions" +msgstr "清除/删除所有分区" + +msgid "Assign mount-point for a partition" +msgstr "为分区分配挂载点" + +msgid "Mark/Unmark a partition to be formatted (wipes data)" +msgstr "标记/取消标记要格式化的分区(擦除数据)" + +msgid "Mark/Unmark a partition as encrypted" +msgstr "将分区标记/取消标记为加密" + +msgid "Mark/Unmark a partition as bootable (automatic for /boot)" +msgstr "将分区标记/取消标记为可引导(自动为 /boot)" + +msgid "Set desired filesystem for a partition" +msgstr "为分区设置所需的文件系统" + +msgid "Abort" +msgstr "中止" + +msgid "Hostname" +msgstr "主机名" + +msgid "Not configured, unavailable unless setup manually" +msgstr "未配置,除非手动设置,否则不可用" + +msgid "Timezone" +msgstr "时区" + +msgid "Set/Modify the below options" +msgstr "请设置/修改以下选项" + +msgid "Install" +msgstr "安装" + +msgid "" +"Use ESC to skip\n" +"\n" +msgstr "" +"按 ESC 键跳过\n" +"\n" + +msgid "Suggest partition layout" +msgstr "建议分区布局" + +msgid "Enter a password: " +msgstr "输入密码: " + +msgid "Enter a encryption password for {}" +msgstr "输入 {} 的加密密码" + +msgid "Enter disk encryption password (leave blank for no encryption): " +msgstr "输入磁盘加密密码(留空表示不加密): " + +msgid "Create a required super-user with sudo privileges: " +msgstr "创建具有 sudo 权限的必需超级用户: " + +msgid "Enter root password (leave blank to disable root): " +msgstr "输入 root 密码(留空以禁用 root): " + +msgid "Password for user \"{}\": " +msgstr "用户“{}”的密码: " + +msgid "Verifying that additional packages exist (this might take a few seconds)" +msgstr "验证是否存在其他软件包(这可能需要几秒钟)" + +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "是否要对默认时间服务器使用自动时间同步 (NTP)?\n" + +msgid "" +"Hardware time and other post-configuration steps might be required in order for NTP to work.\n" +"For more information, please check the Arch wiki" +msgstr "" +"为了使 NTP 工作,可能需要硬件时间和其他配置后步骤。\n" +"更多信息,请查看 Arch wiki" + +msgid "Enter a username to create an additional user (leave blank to skip): " +msgstr "输入用户名以创建其他用户(留空以跳过): " + +msgid "Use ESC to skip\n" +msgstr "按 ESC 键跳过\n" + +msgid "" +"\n" +" Choose an object from the list, and select one of the available actions for it to execute" +msgstr "" +"\n" +"从列表中选择一个对象,然后为其选择一个可用的操作" + +msgid "Cancel" +msgstr "取消" + +msgid "Confirm and exit" +msgstr "确认并退出" + +msgid "Add" +msgstr "添加" + +msgid "Copy" +msgstr "复制" + +msgid "Edit" +msgstr "编辑" + +msgid "Delete" +msgstr "删除" + +msgid "Select an action for '{}'" +msgstr "为“{}”选择一个操作" + +msgid "Copy to new key:" +msgstr "复制到新密钥:" + +msgid "Unknown nic type: {}. Possible values are {}" +msgstr "未知网卡类型:{}。 可能的值为 {}" + +msgid "" +"\n" +"This is your chosen configuration:" +msgstr "" +"\n" +"这是您选择的配置:" + +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman 已经在运行,最多等待 10 分钟以使其终止。" + +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "预先存在的 pacman 锁从未退出。 请在使用 archinstall 之前清理所有现有的 pacman 会话。" + +msgid "Choose which optional additional repositories to enable" +msgstr "选择要启用的可选附加仓库" + +msgid "Add a user" +msgstr "添加一个用户" + +msgid "Change password" +msgstr "修改密码" + +msgid "Promote/Demote user" +msgstr "提升/降级用户" + +msgid "Delete User" +msgstr "删除用户" + +msgid "" +"\n" +"Define a new user\n" +msgstr "" +"\n" +"定义新用户\n" + +msgid "User Name : " +msgstr "用户名: " + +msgid "Should {} be a superuser (sudoer)?" +msgstr "{} 应该是超级用户 (sudoer) 吗?" + +msgid "Define users with sudo privilege: " +msgstr "定义具有 sudo 权限的用户: " + +msgid "No network configuration" +msgstr "无网络配置" + +msgid "Set desired subvolumes on a btrfs partition" +msgstr "在 btrfs 分区上设置所需的子卷" + +msgid "" +"{}\n" +"\n" +"Select which partition to set subvolumes on" +msgstr "" +"{}\n" +"\n" +"选择要在哪个分区上设置子卷" + +msgid "Manage btrfs subvolumes for current partition" +msgstr "管理当前分区的 btrfs 子卷" + +msgid "No configuration" +msgstr "无配置" + +msgid "Save user configuration" +msgstr "保存用户配置" + +msgid "Save user credentials" +msgstr "保存用户凭据" + +msgid "Save disk layout" +msgstr "保存磁盘布局" + +msgid "Save all" +msgstr "全部保存" + +msgid "Choose which configuration to save" +msgstr "选择要保存的配置" + +msgid "Enter a directory for the configuration(s) to be saved: " +msgstr "输入要保存配置的目录: " + +msgid "Not a valid directory: {}" +msgstr "不是有效的目录:{}" + +msgid "The password you are using seems to be weak," +msgstr "您使用的密码似乎很弱," + +msgid "are you sure you want to use it?" +msgstr "你确定要使用它吗?" + +msgid "Optional repositories" +msgstr "可选仓库" + +msgid "Save configuration" +msgstr "保存配置" + +msgid "Missing configurations:\n" +msgstr "缺少配置:\n" + +msgid "Either root-password or at least 1 superuser must be specified" +msgstr "必须指定 root 密码或至少 1 个超级用户" + +msgid "Manage superuser accounts: " +msgstr "管理超级用户帐户: " + +msgid "Manage ordinary user accounts: " +msgstr "管理普通用户账户: " + +msgid " Subvolume :{:16}" +msgstr " 子卷 :{:16}" + +msgid " mounted at {:16}" +msgstr " 安装在 {:16}" + +msgid " with option {}" +msgstr " 带选项 {}" + +msgid "" +"\n" +" Fill the desired values for a new subvolume \n" +msgstr "" +"\n" +" 为新的子卷填充所需的值\n" + +msgid "Subvolume name " +msgstr "子卷名 " + +msgid "Subvolume mountpoint" +msgstr "子卷挂载点" + +msgid "Subvolume options" +msgstr "子卷选项" + +msgid "Save" +msgstr "保存" + +msgid "Subvolume name :" +msgstr "子卷名称:" + +msgid "Select a mount point :" +msgstr "选择挂载点:" + +msgid "Select the desired subvolume options " +msgstr "选择所需的子卷选项 " + +msgid "Define users with sudo privilege, by username: " +msgstr "通过用户名定义具有 sudo 权限的用户: " + +msgid "[!] A log file has been created here: {}" +msgstr "[!] 已在此处创建日志文件:{}" + +msgid "Would you like to use BTRFS subvolumes with a default structure?" +msgstr "您想使用具有默认结构的 BTRFS 子卷吗?" + +msgid "Would you like to use BTRFS compression?" +msgstr "您想使用 BTRFS 压缩吗?" + +msgid "Would you like to create a separate partition for /home?" +msgstr "您想为 /home 创建一个单独的分区吗?" + +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "所选驱动器没有自动建议所需的最小容量\n" + +msgid "Minimum capacity for /home partition: {}GB\n" +msgstr "/home 分区的最小容量:{}GB\n" + +msgid "Minimum capacity for Arch Linux partition: {}GB" +msgstr "Arch Linux 分区的最小容量:{}GB" + +msgid "Continue" +msgstr "继续" + +msgid "yes" +msgstr "是" + +msgid "no" +msgstr "否" + +msgid "set: {}" +msgstr "设置:{}" + +msgid "Manual configuration setting must be a list" +msgstr "手动配置设置必须是列表" + +msgid "No iface specified for manual configuration" +msgstr "没有为手动配置指定 iface" + +msgid "Manual nic configuration with no auto DHCP requires an IP address" +msgstr "没有自动 DHCP 的手动 nic 配置需要 IP 地址" + +msgid "Add interface" +msgstr "添加接口" + +msgid "Edit interface" +msgstr "编辑接口" + +msgid "Delete interface" +msgstr "删除接口" + +msgid "Select interface to add" +msgstr "选择要添加的接口" + +msgid "Manual configuration" +msgstr "手动配置" + +msgid "Mark/Unmark a partition as compressed (btrfs only)" +msgstr "将分区标记/取消标记为压缩(仅限 btrfs)" + +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "您使用的密码似乎很弱,您确定要使用吗?" + +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "提供一系列桌面环境和平铺窗口管理器,例如 gnome, kde, sway" + +msgid "Select your desired desktop environment" +msgstr "选择您想要的桌面环境" + +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "一个非常基本的安装,允许您根据需要自定义 Arch Linux。" + +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "提供一系列可供安装和启用的服务器包,例如 httpd、nginx、mariadb" + +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "选择要安装的服务器,如果没有,则进行最小安装" + +msgid "Installs a minimal system as well as xorg and graphics drivers." +msgstr "安装最小系统以及 xorg 和图形驱动程序。" + +msgid "Press Enter to continue." +msgstr "按回车键继续。" + +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "您想 chroot 进入新创建的安装并执行安装后配置吗?" + +msgid "Are you sure you want to reset this setting?" +msgstr "您确定要重置此设置吗?" + +msgid "Select one or more hard drives to use and configure\n" +msgstr "选择一个或多个硬盘驱动器来使用和配置\n" + +msgid "Any modifications to the existing setting will reset the disk layout!" +msgstr "对现有设置的任何修改都将重置磁盘布局!" + +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "如果您重置硬盘驱动器选择,这也将重置当前磁盘布局。 你确定吗?" + +msgid "Save and exit" +msgstr "保存并退出" + +msgid "" +"{}\n" +"contains queued partitions, this will remove those, are you sure?" +msgstr "" +"{}\n" +"包含排队的分区,这将删除那些,你确定吗?" + +msgid "No audio server" +msgstr "没有音频服务器" + +msgid "(default)" +msgstr "(默认)" + +msgid "Use ESC to skip" +msgstr "按 ESC 键跳过" + +msgid "" +"Use CTRL+C to reset current selection\n" +"\n" +msgstr "使用 CTRL+C 可重置当前选项\n" + +msgid "Copy to: " +msgstr "复制到: " + +msgid "Edit: " +msgstr "编辑: " + +msgid "Key: " +msgstr "键: " + +msgid "Edit {}: " +msgstr "编辑 {}: " + +msgid "Add: " +msgstr "添加: " + +msgid "Value: " +msgstr "值: " + +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "您可以跳过选择驱动器和分区并使用安装在 /mnt 的任何驱动器设置(实验性)" + +msgid "Select one of the disks or skip and use /mnt as default" +msgstr "选择其中一个磁盘或跳过并使用 /mnt 作为默认值" + +msgid "Select which partitions to mark for formatting:" +msgstr "选择要标记为格式化的分区:" + +msgid "Use HSM to unlock encrypted drive" +msgstr "使用 HSM 解锁加密驱动器" + +msgid "Device" +msgstr "设备" + +msgid "Size" +msgstr "大小" + +msgid "Free space" +msgstr "空闲空间" + +msgid "Bus-type" +msgstr "总线类型" + +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "必须指定 root 密码或至少 1 个具有 sudo 权限的用户" + +msgid "Enter username (leave blank to skip): " +msgstr "输入用户名(留空跳过): " + +msgid "The username you entered is invalid. Try again" +msgstr "您输入的用户名无效。 再试一次" + +msgid "Should \"{}\" be a superuser (sudo)?" +msgstr "将 \"{}\" 设置为超级用户(sudo)吗?" + +msgid "Select which partitions to encrypt:" +msgstr "选择要加密的分区:" + +msgid "very weak" +msgstr "非常弱" + +msgid "weak" +msgstr "弱" + +msgid "moderate" +msgstr "一般" + +msgid "strong" +msgstr "强" + +msgid "Add subvolume" +msgstr "添加子卷" + +msgid "Edit subvolume" +msgstr "编辑子卷" + +msgid "Delete subvolume" +msgstr "删除子卷" + +msgid "Configured {} interfaces" +msgstr "已配置的 {} 接口" + +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "此选项启用安装期间可能发生的并行下载次数" + +#, python-brace-format +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +" (Enter a value between 1 to {max_downloads})\n" +"Note:" +msgstr "" +"输入要启用的并行下载数。\n" +" (输入一个介于 1 到 {max_downloads} 之间的值)\n" +"提示:" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - 最大值:{max_downloads}(允许 {max_downloads} 次并行下载,一次允许 {max_downloads+1} 次下载)" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - 最小值:1(允许 1 次并行下载,一次允许 2 次下载)" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr " - 禁用/默认:0(禁用并行下载,一次只允许 1 个下载)" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "输入无效! 使用有效输入重试 [1 到 {max_downloads},或 0 到禁用]" + +msgid "Parallel Downloads" +msgstr "并行下载" + +msgid "ESC to skip" +msgstr "按 ESC 键跳过" + +msgid "CTRL+C to reset" +msgstr "按 CTRL+C 重置" + +msgid "TAB to select" +msgstr "按 TAB 选择" + +msgid "[Default value: 0] > " +msgstr "[默认值: 0] > " + +msgid "To be able to use this translation, please install a font manually that supports the language." +msgstr "为了能够使用此翻译,请手动安装支持该语言的字体。" + +msgid "The font should be stored as {}" +msgstr "字体应存储为 {}" |