index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
diff --git a/.github/workflows/bandit.yaml b/.github/workflows/bandit.yaml index 2123ba9d..84c63348 100644 --- a/.github/workflows/bandit.yaml +++ b/.github/workflows/bandit.yaml @@ -6,7 +6,7 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu bandit - name: Security checkup with Bandit - run: bandit -r archinstall || exit 0
\ No newline at end of file + run: bandit -r archinstall || exit 0 diff --git a/.github/workflows/flake8.yaml b/.github/workflows/flake8.yaml index f7cfe064..d9db80e9 100644 --- a/.github/workflows/flake8.yaml +++ b/.github/workflows/flake8.yaml @@ -6,9 +6,9 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python python-pip - run: python -m pip install --upgrade pip - run: pip install flake8 - name: Lint with flake8 - run: flake8
\ No newline at end of file + run: flake8 diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml index 6464b4a2..ab4e6f5f 100644 --- a/.github/workflows/iso-build.yaml +++ b/.github/workflows/iso-build.yaml @@ -26,7 +26,7 @@ jobs: image: archlinux:latest options: --privileged steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: pwd - run: find . - run: cat /etc/os-release @@ -43,7 +43,7 @@ jobs: - run: echo -e "git\npython\npython-pip\npython-build\npython-flit\npython-setuptools\npython-wheel" >> /tmp/archlive/packages.x86_64 - run: find /tmp/archlive - run: cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./ - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: Arch Live ISO path: /tmp/archlive/out/*.iso diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index d14d8553..160faa53 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -6,7 +6,7 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python mypy python-pip - run: python -m pip install --upgrade pip - run: pip install fastapi pydantic @@ -15,4 +15,4 @@ jobs: # one day this will be enabled # run: mypy --strict --module archinstall || exit 0 - name: run mypy - run: mypy --follow-imports=silent archinstall/lib/menu/selection_menu.py archinstall/lib/menu/global_menu.py archinstall/lib/models/network_configuration.py archinstall/lib/menu/list_manager.py archinstall/lib/user_interaction/network_conf.py archinstall/lib/models/users.py + run: mypy --follow-imports=silent archinstall/lib/menu/selection_menu.py archinstall/lib/menu/global_menu.py archinstall/lib/models/network_configuration.py archinstall/lib/menu/list_manager.py archinstall/lib/user_interaction/network_conf.py archinstall/lib/models/users.py archinstall/lib/disk/blockdevice.py archinstall/lib/user_interaction/subvolume_config.py archinstall/lib/disk/btrfs/btrfs_helpers.py archinstall/lib/translationhandler.py diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 39ef62c9..568a6e6c 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -7,9 +7,9 @@ jobs: image: archlinux:latest options: --privileged steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python python-pip qemu gcc - run: python -m pip install --upgrade pip - run: pip install pytest - name: Test with pytest - run: python -m pytest || exit 0
\ No newline at end of file + run: python -m pytest || exit 0 diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 6196f9d8..4cd32a93 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -8,9 +8,9 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install dependencies @@ -20,7 +20,7 @@ jobs: - name: Build archinstall run: | python -m build - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: archinstall path: dist/* diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 3d0ec253..dd25a105 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install dependencies @@ -4,7 +4,7 @@ # Contributor: demostanis worlds <demostanis@protonmail.com> pkgname=archinstall -pkgver=2.4.3rc1 +pkgver=2.5.0 #pkgver=$(git describe --long | sed 's/\([^-]*-g\)/r\1/;s/-/./g') pkgrel=1 pkgdesc="Just another guided/automated Arch Linux installer with a twist" @@ -30,13 +30,39 @@ Some additional options that are not needed by most users are hidden behind the ## Running from a declarative configuration file or URL -Prequisites: +Prerequisites: 1. Edit the [configuration file](https://github.com/archlinux/archinstall/blob/master/examples/config-sample.json) according to your requirements. Assuming you are on a Arch Linux live-ISO and booted into EFI mode. # archinstall --config <path to user config file or URL> --disk-layout <path to disk layout config file or URL> --creds <path to user credentials config file or URL> +# Available Languages + +Archinstall is available in different languages which have been contributed and are maintained by the community. +Current translations are listed below and vary in the amount of translations per language +``` +English +Deutsch +Española +Française +Indonesia +Italiano +Nederlands +Polskie +Portugues do Brasil +Português +Svenska +Türkçe +čeština +Русский +اردو +Ελληνικά +தமிழ் +``` + +Any contributions to the translations are more than welcome, and to get started please follow [the guide](https://github.com/archlinux/archinstall/blob/master/archinstall/locales/README.md) + # Help? Submit an issue here on GitHub, or submit a post in the discord help channel.<br> @@ -55,7 +81,8 @@ The guided installer itself is also optional to use if so desired and not forced Archinstall has one fundamental function which is to be a flexible library to manage services, packages and other aspects inside the installed system. This library is in turn used by the provided guided installer but is also for anyone who wants to script their own installations. -Therefore, Archinstall will try its best to not introduce any breaking changes except for major releases which may break backwards compability after notifying about such changes. +Therefore, Archinstall will try its best to not introduce any breaking changes except for major releases which may break backwards compatibility after notifying about such changes. + # Scripting your own installation diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 7edeaa80..44852d4c 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -1,5 +1,6 @@ """Arch Linux installer - guided, templates etc.""" -from argparse import ArgumentParser +import typing +from argparse import ArgumentParser, Namespace from .lib.disk import * from .lib.exceptions import * @@ -40,7 +41,7 @@ from .lib.menu.selection_menu import ( Selector, GeneralMenu ) -from .lib.translation import Translation, DeferredTranslation +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 @@ -50,7 +51,7 @@ from .lib.hsm import ( ) parser = ArgumentParser() -__version__ = "2.5.0" +__version__ = "2.5.1" storage['__version__'] = __version__ # add the custome _ as a builtin, it can now be used anywhere in the @@ -58,10 +59,6 @@ storage['__version__'] = __version__ DeferredTranslation.install() -def set_unicode_font(): - SysCommand('setfont UniCyr_8x16') - - def define_arguments(): """ Define which explicit arguments do we allow. @@ -70,6 +67,7 @@ def define_arguments(): Remember that the property/entry name python assigns to the parameters is the first string defined as argument and dashes inside it '-' are changed to '_' """ + parser.add_argument("-v", "--version", action="version", version="%(prog)s " + __version__) parser.add_argument("--config", nargs="?", help="JSON configuration file or URL") parser.add_argument("--creds", nargs="?", help="JSON credentials configuration file") parser.add_argument("--disk_layouts","--disk_layout","--disk-layouts","--disk-layout",nargs="?", @@ -81,6 +79,8 @@ def define_arguments(): parser.add_argument("--script", default="guided", nargs="?", help="Script to run for installation", type=str) parser.add_argument("--mount-point","--mount_point", nargs="?", type=str, help="Define an alternate mount point for installation") parser.add_argument("--debug", action="store_true", default=False, help="Adds debug info into the log") + parser.add_argument("--offline", action="store_true", default=False, help="Disabled online upstream services such as package search and key-ring auto update.") + parser.add_argument("--no-pkg-lookups", action="store_true", default=False, help="Disabled package validation specifically prior to starting installation.") parser.add_argument("--plugin", nargs="?", type=str) def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, error :bool = False) -> dict: @@ -91,7 +91,7 @@ def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, erro --argument=value --argument = value --argument (boolean as default) - the optional paramters to the function alter a bit its behaviour: + the optional parameters to the function alter a bit its behaviour: * multiple allows multivalued arguments, each value separated by whitespace. They're returned as a list * error. If set any non correctly specified argument-value pair to raise an exception. Else, simply notifies the existence of a problem and continues processing. @@ -104,7 +104,7 @@ def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, erro key = None last_key = None while tmp_list: - element = tmp_list.pop(0) # retreive an element of the list + element = tmp_list.pop(0) # retrieve an element of the list if element.startswith('--'): # is an argument ? if '=' in element: # uses the arg=value syntax ? key, value = [x.strip() for x in element[2:].split('=', 1)] @@ -133,6 +133,24 @@ def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, erro print(f" We ignore the entry {element} as it isn't related to any argument") return config +def cleanup_empty_args(args :typing.Union[Namespace, dict]) -> dict: + """ + Takes arguments (dictionary or argparse Namespace) and removes any + None values. This ensures clean mergers during dict.update(args) + """ + if type(args) == Namespace: + args = vars(args) + + clean_args = {} + for key, val in args.items(): + if type(val) == dict: + val = cleanup_empty_args(val) + + if val is not None: + clean_args[key] = val + + return clean_args + def get_arguments() -> Dict[str, Any]: """ The handling of parameters from the command line Is done on following steps: @@ -160,55 +178,70 @@ def get_arguments() -> Dict[str, Any]: exit(1) # load the parameters. first the known, then the unknowns - config.update(vars(args)) + args = cleanup_empty_args(args) + config.update(args) config.update(parse_unspecified_argument_list(unknowns)) # amend the parameters (check internal consistency) # Installation can't be silent if config is not passed - if args.config is not None : - config["silent"] = args.silent - else: + if args.get('config') is None: config["silent"] = False + else: + config["silent"] = args.get('silent') # avoiding a compatibility issue if 'dry-run' in config: del config['dry-run'] + return config def load_config(): - from .lib.models import NetworkConfiguration """ refine and set some arguments. Formerly at the scripts """ + from .lib.models import NetworkConfiguration + + if (archinstall_lang := arguments.get('archinstall-language', None)) is not None: + arguments['archinstall-language'] = TranslationHandler().get_language_by_name(archinstall_lang) + if arguments.get('harddrives', None) is not None: if type(arguments['harddrives']) is str: arguments['harddrives'] = arguments['harddrives'].split(',') arguments['harddrives'] = [BlockDevice(BlockDev) for BlockDev in arguments['harddrives']] # Temporarily disabling keep_partitions if config file is loaded # Temporary workaround to make Desktop Environments work + if arguments.get('profile', None) is not None: if type(arguments.get('profile', None)) is dict: arguments['profile'] = Profile(None, arguments.get('profile', None)['path']) else: arguments['profile'] = Profile(None, arguments.get('profile', None)) + storage['_desktop_profile'] = arguments.get('desktop-environment', None) + if arguments.get('mirror-region', None) is not None: if type(arguments.get('mirror-region', None)) is dict: arguments['mirror-region'] = arguments.get('mirror-region', None) else: selected_region = arguments.get('mirror-region', None) arguments['mirror-region'] = {selected_region: list_mirrors()[selected_region]} + if arguments.get('sys-language', None) is not None: arguments['sys-language'] = arguments.get('sys-language', 'en_US') + if arguments.get('sys-encoding', None) is not None: arguments['sys-encoding'] = arguments.get('sys-encoding', 'utf-8') + if arguments.get('gfx_driver', None) is not None: storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(arguments.get('gfx_driver', None), None) + if arguments.get('servers', None) is not None: storage['_selected_servers'] = arguments.get('servers', None) + if arguments.get('nic', None) is not None: handler = NetworkConfigurationHandler() handler.parse_arguments(arguments.get('nic')) arguments['nic'] = handler.configuration + if arguments.get('!users', None) is not None or arguments.get('!superusers', None) is not None: users = arguments.get('!users', None) superusers = arguments.get('!superusers', None) @@ -227,8 +260,6 @@ def post_process_arguments(arguments): load_plugin(arguments['plugin']) if arguments.get('disk_layouts', None) is not None: - # if 'disk_layouts' not in storage: - # storage['disk_layouts'] = {} layout_storage = {} if not json_stream_to_structure('--disk_layouts',arguments['disk_layouts'],layout_storage): exit(1) @@ -237,18 +268,17 @@ def post_process_arguments(arguments): arguments['harddrives'] = [disk for disk in layout_storage] # backward compatibility. Change partition.format for partition.wipe for disk in layout_storage: - for i,partition in enumerate(layout_storage[disk].get('partitions',[])): + for i, partition in enumerate(layout_storage[disk].get('partitions',[])): if 'format' in partition: partition['wipe'] = partition['format'] del partition['format'] + elif 'btrfs' in partition: + partition['btrfs']['subvolumes'] = Subvolume.parse_arguments(partition['btrfs']['subvolumes']) arguments['disk_layouts'] = layout_storage load_config() -# to ensure that cyrillic characters work in the installer -# set_unicode_font() - define_arguments() arguments = get_arguments() post_process_arguments(arguments) diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py index 510f7103..2a43174d 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -1,4 +1,6 @@ +import os import json +import stat import logging import pathlib from typing import Optional, Dict @@ -106,23 +108,33 @@ class ConfigurationOutput: def save_user_config(self, dest_path :pathlib.Path = None): if self._is_valid_path(dest_path): - with open(dest_path / self._user_config_file, 'w') as config_file: + target = dest_path / self._user_config_file + + with open(target, 'w') as config_file: config_file.write(self.user_config_to_json()) + os.chmod(str(dest_path / self._user_config_file), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) + def save_user_creds(self, dest_path :pathlib.Path = None): if self._is_valid_path(dest_path): if user_creds := self.user_credentials_to_json(): target = dest_path / self._user_creds_file + with open(target, 'w') as config_file: config_file.write(user_creds) + os.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) + def save_disk_layout(self, dest_path :pathlib.Path = None): if self._is_valid_path(dest_path): if disk_layout := self.disk_layout_to_json(): target = dest_path / self._disk_layout_file + with target.open('w') as config_file: config_file.write(disk_layout) + os.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) + def save(self, dest_path :pathlib.Path = None): if not dest_path: dest_path = self._default_save_path diff --git a/archinstall/lib/disk/blockdevice.py b/archinstall/lib/disk/blockdevice.py index c7b69205..736bacbc 100644 --- a/archinstall/lib/disk/blockdevice.py +++ b/archinstall/lib/disk/blockdevice.py @@ -1,13 +1,11 @@ from __future__ import annotations -import os import json import logging import time -from functools import cached_property -from typing import Optional, Dict, Any, Iterator, Tuple, List, TYPE_CHECKING -# https://stackoverflow.com/a/39757388/929999 -if TYPE_CHECKING: - from .partition import Partition + +from collections import OrderedDict +from dataclasses import dataclass +from typing import Optional, Dict, Any, Iterator, List, TYPE_CHECKING from ..exceptions import DiskError, SysCallError from ..output import log @@ -15,18 +13,44 @@ from ..general import SysCommand from ..storage import storage +if TYPE_CHECKING: + from .partition import Partition + _: Any + + +@dataclass +class BlockSizeInfo: + start: str + end: str + size: str + + +@dataclass +class BlockInfo: + pttype: str + ptuuid: str + size: int + tran: Optional[str] + rota: bool + free_space: Optional[List[BlockSizeInfo]] + + class BlockDevice: def __init__(self, path :str, info :Optional[Dict[str, Any]] = None): if not info: from .helpers import all_blockdevices # If we don't give any information, we need to auto-fill it. # Otherwise any subsequent usage will break. - info = all_blockdevices(partitions=False)[path].info + self.info = all_blockdevices(partitions=False)[path].info + else: + self.info = info - self.path = path - self.info = info + self._path = path self.keep_partitions = True - self.part_cache = {} + self._block_info = self._fetch_information() + self._partitions: Dict[str, 'Partition'] = {} + + self._load_partitions() # TODO: Currently disk encryption is a BIT misleading. # It's actually partition-encryption, but for future-proofing this @@ -35,70 +59,113 @@ class BlockDevice: def __repr__(self, *args :str, **kwargs :str) -> str: return self._str_repr - @cached_property + @property + def path(self) -> str: + return self._path + + @property def _str_repr(self) -> str: - return f"BlockDevice({self.device_or_backfile}, size={self._safe_size}GB, free_space={self._safe_free_space}, bus_type={self.bus_type})" - - @cached_property - def display_info(self) -> str: - columns = { - str(_('Device')): self.device_or_backfile, - str(_('Size')): f'{self._safe_size}GB', - str(_('Free space')): f'{self._safe_free_space}', + return f"BlockDevice({self._device_or_backfile}, size={self.size}GB, free_space={self._safe_free_space()}, bus_type={self.bus_type})" + + def as_json(self) -> Dict[str, Any]: + return { + str(_('Device')): self._device_or_backfile, + str(_('Size')): f'{self.size}GB', + str(_('Free space')): f'{self._safe_free_space()}', str(_('Bus-type')): f'{self.bus_type}' } - padding = max([len(k) for k in columns.keys()]) - - pretty = '' - for k, v in columns.items(): - k = k.ljust(padding, ' ') - pretty += f'{k} = {v}\n' - - return pretty.rstrip() - - def __iter__(self) -> Iterator[Partition]: + def __iter__(self) -> Iterator['Partition']: for partition in self.partitions: yield self.partitions[partition] def __getitem__(self, key :str, *args :str, **kwargs :str) -> Any: if hasattr(self, key): return getattr(self, key) - elif key not in self.info: - raise KeyError(f'{self} does not contain information: "{key}"') - return self.info[key] - def __len__(self) -> int: - return len(self.partitions) + if self.info and key in self.info: + return self.info[key] + + raise KeyError(f'{self.info} does not contain information: "{key}"') def __lt__(self, left_comparitor :'BlockDevice') -> bool: - return self.path < left_comparitor.path + return self._path < left_comparitor.path def json(self) -> str: """ json() has precedence over __dump__, so this is a way to give less/partial information for user readability. """ - return self.path + return self._path def __dump__(self) -> Dict[str, Dict[str, Any]]: return { - self.path : { - 'partuuid' : self.uuid, - 'wipe' : self.info.get('wipe', None), - 'partitions' : [part.__dump__() for part in self.partitions.values()] + self._path: { + 'partuuid': self.uuid, + 'wipe': self.info.get('wipe', None), + 'partitions': [part.__dump__() for part in self.partitions.values()] } } - @property - def partition_type(self) -> str: - output = json.loads(SysCommand(f"lsblk --json -o+PTTYPE {self.path}").decode('UTF-8')) + def _call_lsblk(self, path: str) -> Dict[str, Any]: + output = SysCommand(f'lsblk --json -b -o+SIZE,PTTYPE,ROTA,TRAN,PTUUID {self._path}').decode('UTF-8') + if output: + lsblk_info = json.loads(output) + return lsblk_info + + raise DiskError(f'Failed to read disk "{self.path}" with lsblk') + + def _load_partitions(self): + from .partition import Partition + + self._partitions.clear() + + lsblk_info = self._call_lsblk(self._path) + device = lsblk_info['blockdevices'][0] + self._partitions.clear() + + if children := device.get('children', None): + root = f'/dev/{device["name"]}' + for child in children: + part_id = child['name'].removeprefix(device['name']) + self._partitions[part_id] = Partition(root + part_id, block_device=self, part_id=part_id) + + def _get_free_space(self) -> Optional[List[BlockSizeInfo]]: + # NOTE: parted -s will default to `cancel` on prompt, skipping any partition + # that is "outside" the disk. in /dev/sr0 this is usually the case with Archiso, + # so the free will ignore the ESP partition and just give the "free" space. + # Doesn't harm us, but worth noting in case something weird happens. + try: + output = SysCommand(f"parted -s --machine {self._path} print free").decode('utf-8') + if output: + free_lines = [line for line in output.split('\n') if 'free' in line] + sizes = [] + for free_space in free_lines: + _, start, end, size, *_ = free_space.strip('\r\n;').split(':') + sizes.append(BlockSizeInfo(start, end, size)) + + return sizes + except SysCallError as error: + log(f"Could not get free space on {self._path}: {error}", level=logging.DEBUG) + + return None + + def _fetch_information(self) -> BlockInfo: + lsblk_info = self._call_lsblk(self._path) + device = lsblk_info['blockdevices'][0] + free_space = self._get_free_space() - for device in output['blockdevices']: - return device['pttype'] + return BlockInfo( + pttype=device['pttype'], + ptuuid=device['ptuuid'], + size=device['size'], + tran=device['tran'], + rota=device['rota'], + free_space=free_space + ) - @cached_property - def device_or_backfile(self) -> str: + @property + def _device_or_backfile(self) -> Optional[str]: """ Returns the actual device-endpoint of the BlockDevice. If it's a loop-back-device it returns the back-file, @@ -118,7 +185,7 @@ class BlockDevice: return None @property - def device(self) -> str: + def device(self) -> Optional[str]: """ Returns the device file of the BlockDevice. If it's a loop-back-device it returns the /dev/X device, @@ -126,168 +193,82 @@ class BlockDevice: And if it's a crypto-device it returns the parent device """ if "DEVTYPE" not in self.info: - raise DiskError(f'Could not locate backplane info for "{self.path}"') + raise DiskError(f'Could not locate backplane info for "{self._path}"') if self.info['DEVTYPE'] in ['disk','loop']: - return self.path + return self._path elif self.info['DEVTYPE'][:4] == 'raid': # This should catch /dev/md## raid devices - return self.path + return self._path elif self.info['DEVTYPE'] == 'crypt': if 'pkname' not in self.info: - raise DiskError(f'A crypt device ({self.path}) without a parent kernel device name.') + raise DiskError(f'A crypt device ({self._path}) without a parent kernel device name.') return f"/dev/{self.info['pkname']}" else: - log(f"Unknown blockdevice type for {self.path}: {self.info['DEVTYPE']}", level=logging.DEBUG) - - # if not stat.S_ISBLK(os.stat(full_path).st_mode): - # raise DiskError(f'Selected disk "{full_path}" is not a block device.') - - @property - def partitions(self) -> Dict[str, Partition]: - from .filesystem import Partition - - self.partprobe() - result = SysCommand(['/usr/bin/lsblk', '-J', self.path]) - - if b'not a block device' in result: - raise DiskError(f'Can not read partitions off something that isn\'t a block device: {self.path}') + log(f"Unknown blockdevice type for {self._path}: {self.info['DEVTYPE']}", level=logging.DEBUG) - if not result[:1] == b'{': - raise DiskError('Error getting JSON output from:', f'/usr/bin/lsblk -J {self.path}') - - r = json.loads(result.decode('UTF-8')) - if len(r['blockdevices']) and 'children' in r['blockdevices'][0]: - root_path = f"/dev/{r['blockdevices'][0]['name']}" - for part in r['blockdevices'][0]['children']: - part_id = part['name'][len(os.path.basename(self.path)):] - if part_id not in self.part_cache: - # TODO: Force over-write even if in cache? - if part_id not in self.part_cache or self.part_cache[part_id].size != part['size']: - self.part_cache[part_id] = Partition(root_path + part_id, block_device=self, part_id=part_id) - - return {k: self.part_cache[k] for k in sorted(self.part_cache)} + return None @property - def partition(self) -> Partition: - all_partitions = self.partitions - return [all_partitions[k] for k in all_partitions] + def partition_type(self) -> str: + return self._block_info.pttype @property - def partition_table_type(self) -> int: - # TODO: Don't hardcode :) - # Remove if we don't use this function anywhere - from .filesystem import GPT - return GPT - - @cached_property def uuid(self) -> str: - log('BlockDevice().uuid is untested!', level=logging.WARNING, fg='yellow') - """ - Returns the disk UUID as returned by lsblk. - This is more reliable than relying on /dev/disk/by-partuuid as - it doesn't seam to be able to detect md raid partitions. - """ - return SysCommand(f'blkid -s PTUUID -o value {self.path}').decode('UTF-8') - - @cached_property - def _safe_size(self) -> float: - from .helpers import convert_size_to_gb - - try: - output = json.loads(SysCommand(f"lsblk --json -b -o+SIZE {self.path}").decode('UTF-8')) - except SysCallError: - return -1.0 - - for device in output['blockdevices']: - return convert_size_to_gb(device['size']) + return self._block_info.ptuuid - @cached_property + @property def size(self) -> float: from .helpers import convert_size_to_gb + return convert_size_to_gb(self._block_info.size) - output = json.loads(SysCommand(f"lsblk --json -b -o+SIZE {self.path}").decode('UTF-8')) - - for device in output['blockdevices']: - return convert_size_to_gb(device['size']) - - @cached_property - def bus_type(self) -> str: - output = json.loads(SysCommand(f"lsblk --json -o+ROTA,TRAN {self.path}").decode('UTF-8')) - - for device in output['blockdevices']: - return device['tran'] + @property + def bus_type(self) -> Optional[str]: + return self._block_info.tran - @cached_property + @property def spinning(self) -> bool: - output = json.loads(SysCommand(f"lsblk --json -o+ROTA,TRAN {self.path}").decode('UTF-8')) + return self._block_info.rota - for device in output['blockdevices']: - return device['rota'] is True + @property + def partitions(self) -> Dict[str, 'Partition']: + return OrderedDict(sorted(self._partitions.items())) - @cached_property - def _safe_free_space(self) -> Tuple[str, ...]: - try: - return '+'.join(part[2] for part in self.free_space) - except SysCallError: - return '?' + @property + def partition(self) -> List['Partition']: + return list(self.partitions.values()) - @cached_property - def free_space(self) -> Tuple[str, ...]: - # NOTE: parted -s will default to `cancel` on prompt, skipping any partition - # that is "outside" the disk. in /dev/sr0 this is usually the case with Archiso, - # so the free will ignore the ESP partition and just give the "free" space. - # Doesn't harm us, but worth noting in case something weird happens. - try: - for line in SysCommand(f"parted -s --machine {self.path} print free"): - if 'free' in (free_space := line.decode('UTF-8')): - _, start, end, size, *_ = free_space.strip('\r\n;').split(':') - yield (start, end, size) - except SysCallError as error: - log(f"Could not get free space on {self.path}: {error}", level=logging.DEBUG) - - @cached_property - def largest_free_space(self) -> List[str]: - info = [] - for space_info in self.free_space: - if not info: - info = space_info - else: - # [-1] = size - if space_info[-1] > info[-1]: - info = space_info - return info - - @cached_property + @property def first_free_sector(self) -> str: - if info := self.largest_free_space: - start = info[0] + if block_size := self._largest_free_space(): + return block_size.start else: - start = '512MB' - return start + return '512MB' - @cached_property + @property def first_end_sector(self) -> str: - if info := self.largest_free_space: - end = info[1] + if block_size := self._largest_free_space(): + return block_size.end else: - end = f"{self.size}GB" - return end - - def partprobe(self) -> bool: - return SysCommand(['partprobe', self.path]).exit_code == 0 + return f"{self.size}GB" + + def _safe_free_space(self) -> str: + if self._block_info.free_space: + sizes = [free_space.size for free_space in self._block_info.free_space] + return '+'.join(sizes) + return '?' + + def _largest_free_space(self) -> Optional[BlockSizeInfo]: + if self._block_info.free_space: + sorted_sizes = sorted(self._block_info.free_space, key=lambda x: x.size, reverse=True) + return sorted_sizes[0] + return None - def has_partitions(self) -> int: - return len(self.partitions) - - def has_mount_point(self, mountpoint :str) -> bool: - for partition in self.partitions: - if self.partitions[partition].mountpoint == mountpoint: - return True - return False + def _partprobe(self) -> bool: + return SysCommand(['partprobe', self._path]).exit_code == 0 def flush_cache(self) -> None: - self.part_cache = {} + self._load_partitions() def get_partition(self, uuid :Optional[str] = None, partuuid :Optional[str] = None) -> Partition: if not uuid and not partuuid: @@ -296,9 +277,9 @@ class BlockDevice: for count in range(storage.get('DISK_RETRY_ATTEMPTS', 5)): for partition_index, partition in self.partitions.items(): try: - if uuid and partition.uuid.lower() == uuid.lower(): + if uuid and partition.uuid and partition.uuid.lower() == uuid.lower(): return partition - elif partuuid and partition.part_uuid.lower() == partuuid.lower(): + elif partuuid and partition.part_uuid and partition.part_uuid.lower() == partuuid.lower(): return partition except DiskError as error: # Most likely a blockdevice that doesn't support or use UUID's @@ -307,9 +288,10 @@ class BlockDevice: pass log(f"uuid {uuid} or {partuuid} not found. Waiting {storage.get('DISK_TIMEOUTS', 1) * count}s for next attempt",level=logging.DEBUG) + self.flush_cache() time.sleep(storage.get('DISK_TIMEOUTS', 1) * count) - + log(f"Could not find {uuid}/{partuuid} in disk after 5 retries", level=logging.INFO) - log(f"Cache: {self.part_cache}") + log(f"Cache: {self._partitions}") log(f"Partitions: {self.partitions.items()}") raise DiskError(f"Partition {uuid}/{partuuid} was never found on {self} despite several attempts.") diff --git a/archinstall/lib/disk/btrfs/__init__.py b/archinstall/lib/disk/btrfs/__init__.py index 84b9c0f6..a26e0160 100644 --- a/archinstall/lib/disk/btrfs/__init__.py +++ b/archinstall/lib/disk/btrfs/__init__.py @@ -2,8 +2,7 @@ from __future__ import annotations import pathlib import glob import logging -import re -from typing import Union, Dict, TYPE_CHECKING, Any, Iterator +from typing import Union, Dict, TYPE_CHECKING # https://stackoverflow.com/a/39757388/929999 if TYPE_CHECKING: @@ -15,30 +14,15 @@ from .btrfs_helpers import ( setup_subvolumes as setup_subvolumes, mount_subvolume as mount_subvolume ) -from .btrfssubvolume import BtrfsSubvolume as BtrfsSubvolume +from .btrfssubvolumeinfo import BtrfsSubvolumeInfo as BtrfsSubvolume from .btrfspartition import BTRFSPartition as BTRFSPartition -from ..helpers import get_mount_info from ...exceptions import DiskError, Deprecated from ...general import SysCommand from ...output import log -from ...exceptions import SysCallError -def get_subvolume_info(path :pathlib.Path) -> Dict[str, Any]: - try: - output = SysCommand(f"btrfs subvol show {path}").decode() - except SysCallError as error: - print('Error:', error) - result = {} - for line in output.replace('\r\n', '\n').split('\n'): - if ':' in line: - key, val = line.replace('\t', '').split(':', 1) - result[key.strip().lower().replace(' ', '_')] = val.strip() - - return result - -def create_subvolume(installation :Installer, subvolume_location :Union[pathlib.Path, str]) -> bool: +def create_subvolume(installation: Installer, subvolume_location :Union[pathlib.Path, str]) -> bool: """ This function uses btrfs to create a subvolume. @@ -70,113 +54,3 @@ def create_subvolume(installation :Installer, subvolume_location :Union[pathlib. log(f"Creating a subvolume on {target}", level=logging.INFO) if (cmd := SysCommand(f"btrfs subvolume create {target}")).exit_code != 0: raise DiskError(f"Could not create a subvolume at {target}: {cmd}") - -def _has_option(option :str,options :list) -> bool: - """ auxiliary routine to check if an option is present in a list. - we check if the string appears in one of the options, 'cause it can appear in severl forms (option, option=val,...) - """ - if not options: - return False - - for item in options: - if option in item: - return True - - return False - -def manage_btrfs_subvolumes(installation :Installer, - partition :Dict[str, str],) -> list: - - raise Deprecated("Use setup_subvolumes() instead.") - - from copy import deepcopy - """ we do the magic with subvolumes in a centralized place - parameters: - * the installation object - * the partition dictionary entry which represents the physical partition - returns - * mountpoinst, the list which contains all the "new" partititon to be mounted - - We expect the partition has been mounted as / , and it to be unmounted after the processing - Then we create all the subvolumes inside btrfs as demand - We clone then, both the partition dictionary and the object inside it and adapt it to the subvolume needs - Then we return a list of "new" partitions to be processed as "normal" partitions - # TODO For encrypted devices we need some special processing prior to it - """ - # We process each of the pairs <subvolume name: mount point | None | mount info dict> - # th mount info dict has an entry for the path of the mountpoint (named 'mountpoint') and 'options' which is a list - # of mount options (or similar used by brtfs) - mountpoints = [] - subvolumes = partition['btrfs']['subvolumes'] - for name, right_hand in subvolumes.items(): - try: - # we normalize the subvolume name (getting rid of slash at the start if exists. In our implemenation has no semantic load - every subvolume is created from the top of the hierarchy- and simplifies its further use - if name.startswith('/'): - name = name[1:] - # renormalize the right hand. - location = None - subvol_options = [] - # no contents, so it is not to be mounted - if not right_hand: - location = None - # just a string. per backward compatibility the mount point - elif isinstance(right_hand,str): - location = right_hand - # a dict. two elements 'mountpoint' (obvious) and and a mount options list ¿? - elif isinstance(right_hand,dict): - location = right_hand.get('mountpoint',None) - subvol_options = right_hand.get('options',[]) - # we create the subvolume - create_subvolume(installation,name) - # Make the nodatacow processing now - # It will be the main cause of creation of subvolumes which are not to be mounted - # it is not an options which can be established by subvolume (but for whole file systems), and can be - # set up via a simple attribute change in a directory (if empty). And here the directories are brand new - if 'nodatacow' in subvol_options: - if (cmd := SysCommand(f"chattr +C {installation.target}/{name}")).exit_code != 0: - raise DiskError(f"Could not set nodatacow attribute at {installation.target}/{name}: {cmd}") - # entry is deleted so nodatacow doesn't propagate to the mount options - del subvol_options[subvol_options.index('nodatacow')] - # Make the compress processing now - # it is not an options which can be established by subvolume (but for whole file systems), and can be - # set up via a simple attribute change in a directory (if empty). And here the directories are brand new - # in this way only zstd compression is activaded - # TODO WARNING it is not clear if it should be a standard feature, so it might need to be deactivated - if 'compress' in subvol_options: - if not _has_option('compress',partition.get('filesystem',{}).get('mount_options',[])): - if (cmd := SysCommand(f"chattr +c {installation.target}/{name}")).exit_code != 0: - raise DiskError(f"Could not set compress attribute at {installation.target}/{name}: {cmd}") - # entry is deleted so compress doesn't propagate to the mount options - del subvol_options[subvol_options.index('compress')] - # END compress processing. - # we do not mount if THE basic partition will be mounted or if we exclude explicitly this subvolume - if not partition['mountpoint'] and location is not None: - # we begin to create a fake partition entry. First we copy the original -the one that corresponds to - # the primary partition. We make a deepcopy to avoid altering the original content in any case - fake_partition = deepcopy(partition) - # we start to modify entries in the "fake partition" to match the needs of the subvolumes - # to avoid any chance of entering in a loop (not expected) we delete the list of subvolumes in the copy - del fake_partition['btrfs'] - fake_partition['encrypted'] = False - fake_partition['generate-encryption-key-file'] = False - # Mount destination. As of now the right hand part - fake_partition['mountpoint'] = location - # we load the name in an attribute called subvolume, but i think it is not needed anymore, 'cause the mount logic uses a different path. - fake_partition['subvolume'] = name - # here we add the special mount options for the subvolume, if any. - # if the original partition['options'] is not a list might give trouble - if fake_partition.get('filesystem',{}).get('mount_options',[]): - fake_partition['filesystem']['mount_options'].extend(subvol_options) - else: - fake_partition['filesystem']['mount_options'] = subvol_options - # Here comes the most exotic part. The dictionary attribute 'device_instance' contains an instance of Partition. This instance will be queried along the mount process at the installer. - # As the rest will query there the path of the "partition" to be mounted, we feed it with the bind name needed to mount subvolumes - # As we made a deepcopy we have a fresh instance of this object we can manipulate problemless - fake_partition['device_instance'].path = f"{partition['device_instance'].path}[/{name}]" - - # Well, now that this "fake partition" is ready, we add it to the list of the ones which are to be mounted, - # as "normal" ones - mountpoints.append(fake_partition) - except Exception as e: - raise e - return mountpoints diff --git a/archinstall/lib/disk/btrfs/btrfs_helpers.py b/archinstall/lib/disk/btrfs/btrfs_helpers.py index d577d82b..f6d2734a 100644 --- a/archinstall/lib/disk/btrfs/btrfs_helpers.py +++ b/archinstall/lib/disk/btrfs/btrfs_helpers.py @@ -1,72 +1,73 @@ -import pathlib import logging -from typing import Optional +import re +from pathlib import Path +from typing import Optional, Dict, Any, TYPE_CHECKING +from ...models.subvolume import Subvolume from ...exceptions import SysCallError, DiskError from ...general import SysCommand from ...output import log +from ...plugins import plugins from ..helpers import get_mount_info -from .btrfssubvolume import BtrfsSubvolume +from .btrfssubvolumeinfo import BtrfsSubvolumeInfo +if TYPE_CHECKING: + from .btrfspartition import BTRFSPartition + from ...installer import Installer -def mount_subvolume(installation, device, name, subvolume_information): - # we normalize the subvolume name (getting rid of slash at the start if exists. In our implemenation has no semantic load. - # Every subvolume is created from the top of the hierarchy- and simplifies its further use - name = name.lstrip('/') - # renormalize the right hand. - mountpoint = subvolume_information.get('mountpoint', None) - if not mountpoint: - return None +class fstab_btrfs_compression_plugin(): + def __init__(self, partition_dict): + self.partition_dict = partition_dict + + def on_genfstab(self, installation): + with open(f"{installation.target}/etc/fstab", 'r') as fh: + fstab = fh.read() + + # Replace the {installation}/etc/fstab with entries + # using the compress=zstd where the mountpoint has compression set. + with open(f"{installation.target}/etc/fstab", 'w') as fh: + for line in fstab.split('\n'): + # So first we grab the mount options by using subvol=.*? as a locator. + # And we also grab the mountpoint for the entry, for instance /var/log + if (subvoldef := re.findall(',.*?subvol=.*?[\t ]', line)) and (mountpoint := re.findall('[\t ]/.*?[\t ]', line)): + for subvolume in self.partition_dict.get('btrfs', {}).get('subvolumes', []): + # We then locate the correct subvolume and check if it's compressed + if subvolume.compress and subvolume.mountpoint == mountpoint[0].strip(): + # We then sneak in the compress=zstd option if it doesn't already exist: + # We skip entries where compression is already defined + if ',compress=zstd,' not in line: + line = line.replace(subvoldef[0], f",compress=zstd{subvoldef[0]}") + break + + fh.write(f"{line}\n") - if type(mountpoint) == str: - mountpoint = pathlib.Path(mountpoint) + return True - installation_target = installation.target - if type(installation_target) == str: - installation_target = pathlib.Path(installation_target) + +def mount_subvolume(installation: 'Installer', device: 'BTRFSPartition', subvolume: Subvolume): + # we normalize the subvolume name (getting rid of slash at the start if exists. + # In our implementation has no semantic load. + # Every subvolume is created from the top of the hierarchy- and simplifies its further use + name = subvolume.name.lstrip('/') + mountpoint = Path(subvolume.mountpoint) + installation_target = Path(installation.target) mountpoint = installation_target / mountpoint.relative_to(mountpoint.anchor) mountpoint.mkdir(parents=True, exist_ok=True) - - mount_options = subvolume_information.get('options', []) - if not any('subvol=' in x for x in mount_options): - mount_options += [f'subvol={name}'] + mount_options = subvolume.options + [f'subvol={name}'] log(f"Mounting subvolume {name} on {device} to {mountpoint}", level=logging.INFO, fg="gray") SysCommand(f"mount {device.path} {mountpoint} -o {','.join(mount_options)}") -def setup_subvolumes(installation, partition_dict): - """ - Taken from: ..user_guides.py - - partition['btrfs'] = { - "subvolumes" : { - "@": "/", - "@home": "/home", - "@log": "/var/log", - "@pkg": "/var/cache/pacman/pkg", - "@.snapshots": "/.snapshots" - } - } - """ +def setup_subvolumes(installation: 'Installer', partition_dict: Dict[str, Any]): log(f"Setting up subvolumes: {partition_dict['btrfs']['subvolumes']}", level=logging.INFO, fg="gray") - for name, right_hand in partition_dict['btrfs']['subvolumes'].items(): - # we normalize the subvolume name (getting rid of slash at the start if exists. In our implemenation has no semantic load. - # Every subvolume is created from the top of the hierarchy- and simplifies its further use - name = name.lstrip('/') - # renormalize the right hand. - # mountpoint = None - subvol_options = [] - - match right_hand: - # case str(): # backwards-compatability - # mountpoint = right_hand - case dict(): - # mountpoint = right_hand.get('mountpoint', None) - subvol_options = right_hand.get('options', []) + for subvolume in partition_dict['btrfs']['subvolumes']: + # we normalize the subvolume name (getting rid of slash at the start if exists. In our implementation has no semantic load. + # Every subvolume is created from the top of the hierarchy- and simplifies its further use + name = subvolume.name.lstrip('/') # We create the subvolume using the BTRFSPartition instance. # That way we ensure not only easy access, but also accurate mount locations etc. @@ -76,27 +77,28 @@ def setup_subvolumes(installation, partition_dict): # It will be the main cause of creation of subvolumes which are not to be mounted # it is not an options which can be established by subvolume (but for whole file systems), and can be # set up via a simple attribute change in a directory (if empty). And here the directories are brand new - if 'nodatacow' in subvol_options: + if subvolume.nodatacow: if (cmd := SysCommand(f"chattr +C {installation.target}/{name}")).exit_code != 0: raise DiskError(f"Could not set nodatacow attribute at {installation.target}/{name}: {cmd}") - # entry is deleted so nodatacow doesn't propagate to the mount options - del subvol_options[subvol_options.index('nodatacow')] + # Make the compress processing now # it is not an options which can be established by subvolume (but for whole file systems), and can be # set up via a simple attribute change in a directory (if empty). And here the directories are brand new # in this way only zstd compression is activaded # TODO WARNING it is not clear if it should be a standard feature, so it might need to be deactivated - if 'compress' in subvol_options: + if subvolume.compress: if not any(['compress' in filesystem_option for filesystem_option in partition_dict.get('filesystem', {}).get('mount_options', [])]): if (cmd := SysCommand(f"chattr +c {installation.target}/{name}")).exit_code != 0: raise DiskError(f"Could not set compress attribute at {installation.target}/{name}: {cmd}") - # entry is deleted so compress doesn't propagate to the mount options - del subvol_options[subvol_options.index('compress')] -def subvolume_info_from_path(path :pathlib.Path) -> Optional[BtrfsSubvolume]: + if 'fstab_btrfs_compression_plugin' not in plugins: + plugins['fstab_btrfs_compression_plugin'] = fstab_btrfs_compression_plugin(partition_dict) + + +def subvolume_info_from_path(path: Path) -> Optional[BtrfsSubvolumeInfo]: try: - subvolume_name = None + subvolume_name = '' result = {} for index, line in enumerate(SysCommand(f"btrfs subvolume show {path}")): if index == 0: @@ -110,14 +112,14 @@ def subvolume_info_from_path(path :pathlib.Path) -> Optional[BtrfsSubvolume]: # allows for hooking in a pre-processor to do this we have to do it here: result[key.lower().replace(' ', '_').replace('(s)', 's')] = value.strip() - return BtrfsSubvolume(**{'full_path' : path, 'name' : subvolume_name, **result}) - + return BtrfsSubvolumeInfo(**{'full_path' : path, 'name' : subvolume_name, **result}) # type: ignore except SysCallError as error: log(f"Could not retrieve subvolume information from {path}: {error}", level=logging.WARNING, fg="orange") return None -def find_parent_subvolume(path :pathlib.Path, filters=[]): + +def find_parent_subvolume(path: Path, filters=[]) -> Optional[BtrfsSubvolumeInfo]: # A root path cannot have a parent if str(path) == '/': return None @@ -127,6 +129,8 @@ def find_parent_subvolume(path :pathlib.Path, filters=[]): if found_mount['target'] == '/': return None - return find_parent_subvolume(path.parent, traverse=True, filters=[*filters, found_mount['target']]) + return find_parent_subvolume(path.parent, filters=[*filters, found_mount['target']]) - return subvolume
\ No newline at end of file + return subvolume + + return None diff --git a/archinstall/lib/disk/btrfs/btrfspartition.py b/archinstall/lib/disk/btrfs/btrfspartition.py index 5020133d..d04c9b98 100644 --- a/archinstall/lib/disk/btrfs/btrfspartition.py +++ b/archinstall/lib/disk/btrfs/btrfspartition.py @@ -15,24 +15,13 @@ from .btrfs_helpers import ( if TYPE_CHECKING: from ...installer import Installer - from .btrfssubvolume import BtrfsSubvolume + from .btrfssubvolumeinfo import BtrfsSubvolumeInfo + class BTRFSPartition(Partition): def __init__(self, *args, **kwargs): Partition.__init__(self, *args, **kwargs) - def __repr__(self, *args :str, **kwargs :str) -> str: - mount_repr = '' - if self.mountpoint: - mount_repr = f", mounted={self.mountpoint}" - elif self.target_mountpoint: - mount_repr = f", rel_mountpoint={self.target_mountpoint}" - - if self._encrypted: - return f'BTRFSPartition(path={self.path}, size={self.size}, PARTUUID={self._safe_uuid}, parent={self.real_device}, fs={self.filesystem}{mount_repr})' - else: - return f'BTRFSPartition(path={self.path}, size={self.size}, PARTUUID={self._safe_uuid}, fs={self.filesystem}{mount_repr})' - @property def subvolumes(self): for filesystem in findmnt(pathlib.Path(self.path), recurse=True).get('filesystems', []): @@ -40,17 +29,17 @@ class BTRFSPartition(Partition): yield subvolume_info_from_path(filesystem['target']) def iterate_children(struct): - for child in struct.get('children', []): + for c in struct.get('children', []): if '[' in child.get('source', ''): - yield subvolume_info_from_path(child['target']) + yield subvolume_info_from_path(c['target']) - for sub_child in iterate_children(child): + for sub_child in iterate_children(c): yield sub_child for child in iterate_children(filesystem): yield child - def create_subvolume(self, subvolume :pathlib.Path, installation :Optional['Installer'] = None) -> 'BtrfsSubvolume': + def create_subvolume(self, subvolume :pathlib.Path, installation :Optional['Installer'] = None) -> 'BtrfsSubvolumeInfo': """ Subvolumes have to be created within a mountpoint. This means we need to get the current installation target. @@ -62,13 +51,13 @@ class BTRFSPartition(Partition): if not installation: installation = storage.get('installation_session') - # Determain if the path given, is an absolute path or a releative path. + # Determain if the path given, is an absolute path or a relative path. # We do this by checking if the path contains a known mountpoint. if str(subvolume)[0] == '/': if filesystems := findmnt(subvolume, traverse=True).get('filesystems'): if (target := filesystems[0].get('target')) and target != '/' and str(subvolume).startswith(target): # Path starts with a known mountpoint which isn't / - # Which means it's an absolut path to a mounted location. + # Which means it's an absolute path to a mounted location. pass else: # Since it's not an absolute position with a known start. @@ -108,9 +97,13 @@ class BTRFSPartition(Partition): if glob.glob(str(subvolume / '*')): raise DiskError(f"Cannot create subvolume at {subvolume} because it contains data (non-empty folder target is not supported by BTRFS)") - elif subvolinfo := subvolume_info_from_path(subvolume): - raise DiskError(f"Destination {subvolume} is already a subvolume: {subvolinfo}") + # Ideally we would like to check if the destination is already a subvolume. + # But then we would need the mount-point at this stage as well. + # So we'll comment out this check: + # elif subvolinfo := subvolume_info_from_path(subvolume): + # raise DiskError(f"Destination {subvolume} is already a subvolume: {subvolinfo}") + # And deal with it here: SysCommand(f"btrfs subvolume create {subvolume}") - return subvolume_info_from_path(subvolume)
\ No newline at end of file + return subvolume_info_from_path(subvolume) diff --git a/archinstall/lib/disk/btrfs/btrfssubvolume.py b/archinstall/lib/disk/btrfs/btrfssubvolumeinfo.py index a96e2a94..5f5bdea6 100644 --- a/archinstall/lib/disk/btrfs/btrfssubvolume.py +++ b/archinstall/lib/disk/btrfs/btrfssubvolumeinfo.py @@ -16,8 +16,9 @@ from ...general import SysCommand from ...output import log from ...storage import storage + @dataclass -class BtrfsSubvolume: +class BtrfsSubvolumeInfo: full_path :pathlib.Path name :str uuid :str @@ -68,9 +69,9 @@ class BtrfsSubvolume: from .btrfs_helpers import subvolume_info_from_path # TODO: Make this function traverse storage['MOUNT_POINT'] and find the first - # occurance of a mountpoint that is a btrfs volume instead of lazy assume / is a subvolume. + # occurrence of a mountpoint that is a btrfs volume instead of lazy assume / is a subvolume. # It would also be nice if it could use findmnt(self.full_path) and traverse backwards - # finding the last occurance of a subvolume which 'self' belongs to. + # finding the last occurrence of a subvolume which 'self' belongs to. if volume := subvolume_info_from_path(storage['MOUNT_POINT']): return self.full_path == volume.full_path @@ -188,4 +189,4 @@ class BtrfsSubvolume: def unmount(self, recurse :bool = True): SysCommand(f"umount {'-R' if recurse else ''} {self.full_path}") - log(f"Successfully unmounted {self}", level=logging.INFO, fg="gray")
\ No newline at end of file + log(f"Successfully unmounted {self}", level=logging.INFO, fg="gray") diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py index f94b4b47..5d5952a0 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -74,7 +74,7 @@ class Filesystem: raise KeyError(f"Could not create a GPT label on {self}") elif self.mode == MBR: if not self.parted_mklabel(self.blockdevice.device, "msdos"): - raise KeyError(f"Could not create a MSDOS label on {self}") + raise KeyError(f"Could not create a MS-DOS label on {self}") self.blockdevice.flush_cache() time.sleep(3) @@ -100,7 +100,7 @@ class Filesystem: partition['device_instance'] = self.blockdevice.get_partition(uuid=partition_uuid) except DiskError: partition['device_instance'] = self.blockdevice.get_partition(partuuid=partition_uuid) - + log(_("Re-using partition instance: {}").format(partition['device_instance']), level=logging.DEBUG, fg="gray") else: log(f"{self}.load_layout() doesn't know how to work without 'wipe' being set or UUID ({partition.get('PARTUUID')}) was given and found.", fg="yellow", level=logging.WARNING) @@ -210,7 +210,14 @@ class Filesystem: # TODO: Implement this with declarative profiles instead. raise ValueError("Installation().use_entire_disk() has to be re-worked.") - def add_partition(self, partition_type :str, start :str, end :str, partition_format :Optional[str] = None, skip_mklabel :bool = False) -> Partition: + def add_partition( + self, + partition_type :str, + start :str, + end :str, + partition_format :Optional[str] = None, + skip_mklabel :bool = False + ) -> Partition: log(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO) if len(self.blockdevice.partitions) == 0 and skip_mklabel is False: @@ -221,7 +228,7 @@ class Filesystem: raise KeyError(f"Could not create a GPT label on {self}") elif self.mode == MBR: if not self.parted_mklabel(self.blockdevice.device, "msdos"): - raise KeyError(f"Could not create a MSDOS label on {self}") + raise KeyError(f"Could not create a MS-DOS label on {self}") self.blockdevice.flush_cache() @@ -232,6 +239,7 @@ class Filesystem: except DiskError: pass + # TODO this check should probably run in the setup process rather than during the installation if self.mode == MBR: if len(self.blockdevice.partitions) > 3: DiskError("Too many partitions on disk, MBR disks can only have 3 primary partitions") @@ -245,15 +253,9 @@ class Filesystem: if self.parted(parted_string): for count in range(storage.get('DISK_RETRY_ATTEMPTS', 3)): - self.partprobe() - - new_partition_uuids = [] - for partition in self.blockdevice.partitions.values(): - try: - new_partition_uuids.append(partition.part_uuid) - except DiskError: - pass + self.blockdevice.flush_cache() + new_partition_uuids = [partition.part_uuid for partition in self.blockdevice.partitions.values()] new_partuuid_set = (set(previous_partuuids) ^ set(new_partition_uuids)) if len(new_partuuid_set) and (new_partuuid := new_partuuid_set.pop()): @@ -263,17 +265,23 @@ class Filesystem: log(f'Blockdevice: {self.blockdevice}', level=logging.ERROR, fg="red") log(f'Partitions: {self.blockdevice.partitions}', level=logging.ERROR, fg="red") log(f'Partition set: {new_partuuid_set}', level=logging.ERROR, fg="red") - log(f'New UUID: {[new_partuuid]}', level=logging.ERROR, fg="red") + log(f'New PARTUUID: {[new_partuuid]}', level=logging.ERROR, fg="red") log(f'get_partition(): {self.blockdevice.get_partition}', level=logging.ERROR, fg="red") raise err else: log(f"Could not get UUID for partition. Waiting {storage.get('DISK_TIMEOUTS', 1) * count}s before retrying.",level=logging.DEBUG) - time.sleep(storage.get('DISK_TIMEOUTS', 1) * count) + self.partprobe() + time.sleep(max(0.1, storage.get('DISK_TIMEOUTS', 1))) + else: + print("Parted did not return True during partition creation") + + total_partitions = set([partition.part_uuid for partition in self.blockdevice.partitions.values()]) + total_partitions.update(previous_partuuids) # TODO: This should never be able to happen log(f"Could not find the new PARTUUID after adding the partition.", level=logging.ERROR, fg="red") log(f"Previous partitions: {previous_partuuids}", level=logging.ERROR, fg="red") - log(f"New partitions: {(previous_partuuids ^ {partition.part_uuid for partition in self.blockdevice.partitions.values()})}", level=logging.ERROR, fg="red") + log(f"New partitions: {total_partitions}", level=logging.ERROR, fg="red") raise DiskError(f"Could not add partition using: {parted_string}") def set_name(self, partition: int, name: str) -> bool: diff --git a/archinstall/lib/disk/helpers.py b/archinstall/lib/disk/helpers.py index 99856aad..f19125f4 100644 --- a/archinstall/lib/disk/helpers.py +++ b/archinstall/lib/disk/helpers.py @@ -8,6 +8,8 @@ import time import glob from typing import Union, List, Iterator, Dict, Optional, Any, TYPE_CHECKING # https://stackoverflow.com/a/39757388/929999 +from ..models.subvolume import Subvolume + if TYPE_CHECKING: from .partition import Partition @@ -112,7 +114,7 @@ def cleanup_bash_escapes(data :str) -> str: def blkid(cmd :str) -> Dict[str, Any]: if '-o' in cmd and '-o export' not in cmd: - raise ValueError(f"blkid() requires '-o export' to be used and can therefor not continue reliably.") + raise ValueError(f"blkid() requires '-o export' to be used and can therefore not continue reliably.") elif '-o' not in cmd: cmd += ' -o export' @@ -133,7 +135,7 @@ def blkid(cmd :str) -> Dict[str, Any]: key, val = line.split('=', 1) if key.lower() == 'devname': devname = val - # Lowercase for backwards compatability with all_disks() previous use cases + # Lowercase for backwards compatibility with all_disks() previous use cases result[devname] = { "path": devname, "PATH": devname @@ -218,7 +220,12 @@ def all_blockdevices(mappers=False, partitions=False, error=False) -> Dict[str, # we'll iterate the /sys/class definitions and find the information # from there. for block_device in glob.glob("/sys/class/block/*"): - device_path = f"/dev/{pathlib.Path(block_device).readlink().name}" + device_path = pathlib.Path(f"/dev/{pathlib.Path(block_device).readlink().name}") + + if device_path.exists() is False: + log(f"Unknown device found by '/sys/class/block/*', ignoring: {device_path}", level=logging.WARNING, fg="yellow") + continue + try: information = blkid(f'blkid -p -o export {device_path}') except SysCallError as ex: @@ -227,12 +234,17 @@ def all_blockdevices(mappers=False, partitions=False, error=False) -> Dict[str, try: information = get_loop_info(device_path) if not information: + print("Exit code for blkid -p -o export was:", ex.exit_code) raise SysCallError("Could not get loop information", exit_code=1) except SysCallError: + print("Not a loop device, trying uevent rules.") information = get_blockdevice_uevent(pathlib.Path(block_device).readlink().name) else: + # We could not reliably get any information, perhaps the disk is clean of information? + print("Raising ex because:", ex.exit_code) raise ex + # return instances information = enrich_blockdevice_information(information) @@ -244,7 +256,7 @@ def all_blockdevices(mappers=False, partitions=False, error=False) -> Dict[str, instances[path] = Partition(path, block_device=BlockDevice(get_parent_of_partition(pathlib.Path(path)))) elif path_info.get('PTTYPE', False) is not False or path_info.get('TYPE') == 'loop': instances[path] = BlockDevice(path, path_info) - elif path_info.get('TYPE') == 'squashfs': + elif path_info.get('TYPE') in ('squashfs', 'erofs'): # We can ignore squashfs devices (usually /dev/loop0 on Arch ISO) continue else: @@ -368,7 +380,7 @@ def get_all_targets(data :Dict[str, Any], filters :Dict[str, None] = {}) -> Dict return filters -def get_partitions_in_use(mountpoint :str) -> List[Partition]: +def get_partitions_in_use(mountpoint :str) -> Dict[str, Any]: from .partition import Partition try: @@ -391,12 +403,20 @@ def get_partitions_in_use(mountpoint :str) -> List[Partition]: if not type(blockdev) in (Partition, MapperDev): continue - for blockdev_mountpoint in blockdev.mount_information: - block_devices_mountpoints[blockdev_mountpoint['target']] = blockdev + if isinstance(blockdev, Partition): + for blockdev_mountpoint in blockdev.mountpoints: + block_devices_mountpoints[blockdev_mountpoint] = blockdev + else: + for blockdev_mountpoint in blockdev.mount_information: + block_devices_mountpoints[blockdev_mountpoint['target']] = blockdev log(f'Filtering available mounts {block_devices_mountpoints} to those under {mountpoint}', level=logging.DEBUG) for mountpoint in list(get_all_targets(output['filesystems']).keys()): + # Since all_blockdevices() returns PosixPath objects, we need to convert + # findmnt paths to pathlib.Path() first: + mountpoint = pathlib.Path(mountpoint) + if mountpoint in block_devices_mountpoints: if mountpoint not in mounts: mounts[mountpoint] = block_devices_mountpoints[mountpoint] @@ -433,9 +453,10 @@ def disk_layouts() -> Optional[Dict[str, Any]]: def encrypted_partitions(blockdevices :Dict[str, Any]) -> bool: - for partition in blockdevices.values(): - if partition.get('encrypted', False): - yield partition + 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: @@ -468,13 +489,14 @@ def convert_device_to_uuid(path :str) -> str: raise DiskError(f"Could not retrieve the UUID of {path} within a timely manner.") + def has_mountpoint(partition: Union[dict,Partition,MapperDev], target: str, strict: bool = True) -> bool: """ Determine if a certain partition is mounted (or has a mountpoint) as specific target (path) Coded for clarity rather than performance Input parms: :parm partition the partition we check - :type Either a Partition object or a dict with the contents of a partition definiton in the disk_layouts schema + :type Either a Partition object or a dict with the contents of a partition definition in the disk_layouts schema :parm target (a string representing a mount path we want to check for. :type str @@ -484,10 +506,12 @@ def has_mountpoint(partition: Union[dict,Partition,MapperDev], target: str, stri """ # we create the mountpoint list if isinstance(partition,dict): - subvols = partition.get('btrfs',{}).get('subvolumes',{}) - mountpoints = [partition.get('mountpoint'),] + [subvols[subvol] if isinstance(subvols[subvol],str) or not subvols[subvol] else subvols[subvol].get('mountpoint') for subvol in subvols] + subvolumes: List[Subvolume] = partition.get('btrfs',{}).get('subvolumes', []) + mountpoints = [partition.get('mountpoint')] + mountpoints += [volume.mountpoint for volume in subvolumes] else: mountpoints = [partition.mountpoint,] + [subvol.target for subvol in partition.subvolumes] + # we check if strict or target == '/': if target in mountpoints: diff --git a/archinstall/lib/disk/mapperdev.py b/archinstall/lib/disk/mapperdev.py index 913dbc13..71ef2a79 100644 --- a/archinstall/lib/disk/mapperdev.py +++ b/archinstall/lib/disk/mapperdev.py @@ -10,7 +10,7 @@ from ..general import SysCommand from ..output import log if TYPE_CHECKING: - from .btrfs import BtrfsSubvolume + from .btrfs import BtrfsSubvolumeInfo @dataclass class MapperDev: @@ -37,12 +37,12 @@ class MapperDev: for slave in glob.glob(f"/sys/class/block/{dm_device.name}/slaves/*"): partition_belonging_to_dmcrypt_device = pathlib.Path(slave).name - + try: uevent_data = SysCommand(f"blkid -o export /dev/{partition_belonging_to_dmcrypt_device}").decode() except SysCallError as error: log(f"Could not get information on device /dev/{partition_belonging_to_dmcrypt_device}: {error}", level=logging.ERROR, fg="red") - + information = uevent(uevent_data) block_device = BlockDevice(get_parent_of_partition('/dev/' / pathlib.Path(information['DEVNAME']))) @@ -65,9 +65,13 @@ class MapperDev: return None @property + def mountpoints(self) -> List[Dict[str, Any]]: + return [obj['target'] for obj in self.mount_information] + + @property def mount_information(self) -> List[Dict[str, Any]]: from .helpers import find_mountpoint - return list(find_mountpoint(self.path)) + return [{**obj, 'target' : pathlib.Path(obj.get('target', '/dev/null'))} for obj in find_mountpoint(self.path)] @property def filesystem(self) -> Optional[str]: @@ -75,10 +79,10 @@ class MapperDev: return get_filesystem_type(self.path) @property - def subvolumes(self) -> Iterator['BtrfsSubvolume']: + def subvolumes(self) -> Iterator['BtrfsSubvolumeInfo']: from .btrfs import subvolume_info_from_path for mountpoint in self.mount_information: if target := mountpoint.get('target'): if subvolume := subvolume_info_from_path(pathlib.Path(target)): - yield subvolume
\ No newline at end of file + yield subvolume diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py index 73c88597..56a7d436 100644 --- a/archinstall/lib/disk/partition.py +++ b/archinstall/lib/disk/partition.py @@ -1,60 +1,83 @@ import glob -import pathlib import time import logging import json import os import hashlib +import typing +from dataclasses import dataclass +from pathlib import Path from typing import Optional, Dict, Any, List, Union, Iterator from .blockdevice import BlockDevice -from .helpers import find_mountpoint, get_filesystem_type, convert_size_to_gb, split_bind_name +from .helpers import get_filesystem_type, convert_size_to_gb, split_bind_name from ..storage import storage from ..exceptions import DiskError, SysCallError, UnknownFilesystemFormat from ..output import log from ..general import SysCommand from .btrfs.btrfs_helpers import subvolume_info_from_path -from .btrfs.btrfssubvolume import BtrfsSubvolume +from .btrfs.btrfssubvolumeinfo import BtrfsSubvolumeInfo + + +@dataclass +class PartitionInfo: + pttype: str + partuuid: str + uuid: str + start: Optional[int] + end: Optional[int] + bootable: bool + size: float + sector_size: int + filesystem_type: str + mountpoints: List[Path] + + def get_first_mountpoint(self) -> Optional[Path]: + if len(self.mountpoints) > 0: + return self.mountpoints[0] + return None + class Partition: - def __init__(self, + def __init__( + self, path: str, block_device: BlockDevice, part_id :Optional[str] = None, filesystem :Optional[str] = None, mountpoint :Optional[str] = None, encrypted :bool = False, - autodetect_filesystem :bool = True): - + autodetect_filesystem :bool = True, + ): if not part_id: part_id = os.path.basename(path) - self.block_device = block_device - if type(self.block_device) is str: + if type(block_device) is str: raise ValueError(f"Partition()'s 'block_device' parameter has to be a archinstall.BlockDevice() instance!") - self.path = path - self.part_id = part_id - self.target_mountpoint = mountpoint - self.filesystem = filesystem + self.block_device = block_device + self._path = path + self._part_id = part_id + self._target_mountpoint = mountpoint self._encrypted = None - self.encrypted = encrypted - self.allow_formatting = False + self._encrypted = encrypted + self._wipe = False + self._type = 'primary' if mountpoint: self.mount(mountpoint) - try: - self.mount_information = list(find_mountpoint(self.path)) - except DiskError: - self.mount_information = [{}] + self._partition_info = self._fetch_information() - if not self.filesystem and autodetect_filesystem: - self.filesystem = get_filesystem_type(path) + if not autodetect_filesystem and filesystem: + self._partition_info.filesystem_type = filesystem - if self.filesystem == 'crypto_LUKS': - self.encrypted = True + if self._partition_info.filesystem_type == 'crypto_LUKS': + self._encrypted = True + # I hate doint this but I'm currently unsure where this + # is acutally used to be able to fix the typing issues properly + @typing.no_type_check def __lt__(self, left_comparitor :BlockDevice) -> bool: if type(left_comparitor) == Partition: left_comparitor = left_comparitor.path @@ -62,147 +85,175 @@ class Partition: left_comparitor = str(left_comparitor) # The goal is to check if /dev/nvme0n1p1 comes before /dev/nvme0n1p5 - return self.path < left_comparitor + return self._path < left_comparitor def __repr__(self, *args :str, **kwargs :str) -> str: mount_repr = '' - if self.mountpoint: - mount_repr = f", mounted={self.mountpoint}" - elif self.target_mountpoint: - mount_repr = f", rel_mountpoint={self.target_mountpoint}" + if mountpoint := self._partition_info.get_first_mountpoint(): + mount_repr = f", mounted={mountpoint}" + elif self._target_mountpoint: + mount_repr = f", rel_mountpoint={self._target_mountpoint}" + + classname = self.__class__.__name__ if self._encrypted: - return f'Partition(path={self.path}, size={self.size}, PARTUUID={self._safe_uuid}, parent={self.real_device}, fs={self.filesystem}{mount_repr})' + return f'{classname}(path={self._path}, size={self.size}, PARTUUID={self.part_uuid}, parent={self.real_device}, fs={self._partition_info.filesystem_type}{mount_repr})' else: - return f'Partition(path={self.path}, size={self.size}, PARTUUID={self._safe_uuid}, fs={self.filesystem}{mount_repr})' + return f'{classname}(path={self._path}, size={self.size}, PARTUUID={self.part_uuid}, fs={self._partition_info.filesystem_type}{mount_repr})' + + def as_json(self) -> Dict[str, Any]: + """ + this is used for the table representation of the partition (see FormattedOutput) + """ + partition_info = { + 'type': self._type, + 'PARTUUID': self.part_uuid, + 'wipe': self._wipe, + 'boot': self.boot, + 'ESP': self.boot, + 'mountpoint': self._target_mountpoint, + 'encrypted': self._encrypted, + 'start': self.start, + 'size': self.end, + 'filesystem': self._partition_info.filesystem_type + } + + return partition_info def __dump__(self) -> Dict[str, Any]: + # TODO remove this in favour of as_json return { - 'type': 'primary', - 'PARTUUID': self._safe_uuid, - 'wipe': self.allow_formatting, + 'type': self._type, + 'PARTUUID': self.part_uuid, + 'wipe': self._wipe, 'boot': self.boot, 'ESP': self.boot, - 'mountpoint': self.target_mountpoint, + 'mountpoint': self._target_mountpoint, 'encrypted': self._encrypted, 'start': self.start, 'size': self.end, 'filesystem': { - 'format': get_filesystem_type(self.path) + 'format': self._partition_info.filesystem_type } } - @property - def mountpoint(self) -> Optional[str]: - try: - data = json.loads(SysCommand(f"findmnt --json -R {self.path}").decode()) - for filesystem in data['filesystems']: - return pathlib.Path(filesystem.get('target')) + def _call_lsblk(self) -> Dict[str, Any]: + self.partprobe() + # This sleep might be overkill, but lsblk is known to + # work against a chaotic cache that can change during call + # causing no information to be returned (blkid is better) + # time.sleep(1) + # TODO: Maybe incorporate a re-try system here based on time.sleep(max(0.1, storage.get('DISK_TIMEOUTS', 1))) + + try: + output = SysCommand(f"lsblk --json -b -o+LOG-SEC,SIZE,PTTYPE,PARTUUID,UUID,FSTYPE {self.device_path}").decode('UTF-8') except SysCallError as error: - # Not mounted anywhere most likely - log(f"Could not locate mount information for {self.path}: {error}", level=logging.DEBUG, fg="grey") - pass + # It appears as if lsblk can return exit codes like 8192 to indicate something. + # But it does return output so we'll try to catch it. + output = error.worker.decode('UTF-8') - return None + if output: + lsblk_info = json.loads(output) + return lsblk_info - @property - def sector_size(self) -> Optional[int]: - output = json.loads(SysCommand(f"lsblk --json -o+LOG-SEC {self.device_path}").decode('UTF-8')) + raise DiskError(f'Failed to read disk "{self.device_path}" with lsblk') - for device in output['blockdevices']: - return device.get('log-sec', None) + def _call_sfdisk(self) -> Dict[str, Any]: + output = SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8') - @property - def start(self) -> Optional[str]: - output = json.loads(SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8')) + if output: + sfdisk_info = json.loads(output) + partitions = sfdisk_info.get('partitiontable', {}).get('partitions', []) + node = list(filter(lambda x: x['node'] == self._path, partitions)) - for partition in output.get('partitiontable', {}).get('partitions', []): - if partition['node'] == self.path: - return partition['start'] # * self.sector_size + if len(node) > 0: + return node[0] - @property - def end(self) -> Optional[str]: - # TODO: actually this is size in sectors unit - # TODO: Verify that the logic holds up, that 'size' is the size without 'start' added to it. - output = json.loads(SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8')) + return {} + + raise DiskError(f'Failed to read disk "{self.block_device.path}" with sfdisk') + + def _fetch_information(self) -> PartitionInfo: + lsblk_info = self._call_lsblk() + sfdisk_info = self._call_sfdisk() + + if not (device := lsblk_info.get('blockdevices', [None])[0]): + raise DiskError(f'Failed to retrieve information for "{self.device_path}" with lsblk') - for partition in output.get('partitiontable', {}).get('partitions', []): - if partition['node'] == self.path: - return partition['size'] # * self.sector_size + mountpoints = [Path(mountpoint) for mountpoint in device['mountpoints'] if mountpoint] + bootable = sfdisk_info.get('bootable', False) or sfdisk_info.get('type', '') == 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' + + return PartitionInfo( + pttype=device['pttype'], + partuuid=device['partuuid'], + uuid=device['uuid'], + sector_size=device['log-sec'], + size=convert_size_to_gb(device['size']), + start=sfdisk_info.get('start', None), + end=sfdisk_info.get('size', None), + bootable=bootable, + filesystem_type=device['fstype'], + mountpoints=mountpoints + ) @property - def end_sectors(self) -> Optional[str]: - output = json.loads(SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8')) + def target_mountpoint(self) -> Optional[str]: + return self._target_mountpoint - for partition in output.get('partitiontable', {}).get('partitions', []): - if partition['node'] == self.path: - return partition['start'] + partition['size'] + @property + def path(self) -> str: + return self._path @property - def size(self) -> Optional[float]: - for i in range(storage['DISK_RETRY_ATTEMPTS']): - self.partprobe() - time.sleep(max(0.1, storage['DISK_TIMEOUTS'] * i)) + def filesystem(self) -> str: + return self._partition_info.filesystem_type - try: - lsblk = json.loads(SysCommand(f"lsblk --json -b -o+SIZE {self.device_path}").decode()) + @property + def mountpoint(self) -> Optional[Path]: + if len(self.mountpoints) > 0: + return self.mountpoints[0] + return None - for device in lsblk['blockdevices']: - return convert_size_to_gb(device['size']) - except SysCallError as error: - if error.exit_code == 8192: - return None - else: - raise error + @property + def mountpoints(self) -> List[Path]: + return self._partition_info.mountpoints @property - def boot(self) -> bool: - output = json.loads(SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8')) - - # Get the bootable flag from the sfdisk output: - # { - # "partitiontable": { - # "device":"/dev/loop0", - # "partitions": [ - # {"node":"/dev/loop0p1", "start":2048, "size":10483712, "type":"83", "bootable":true} - # ] - # } - # } - - for partition in output.get('partitiontable', {}).get('partitions', []): - if partition['node'] == self.path: - # first condition is for MBR disks, second for GPT disks - return partition.get('bootable', False) or partition.get('type','') == 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' + def sector_size(self) -> int: + return self._partition_info.sector_size - return False + @property + def start(self) -> Optional[int]: + return self._partition_info.start @property - def partition_type(self) -> Optional[str]: - lsblk = json.loads(SysCommand(f"lsblk --json -o+PTTYPE {self.device_path}").decode('UTF-8')) + def end(self) -> Optional[int]: + return self._partition_info.end - for device in lsblk['blockdevices']: - return device['pttype'] + @property + def end_sectors(self) -> Optional[int]: + start = self._partition_info.start + end = self._partition_info.end + if start and end: + return start + end + return None @property - def part_uuid(self) -> Optional[str]: - """ - Returns the PARTUUID as returned by lsblk. - This is more reliable than relying on /dev/disk/by-partuuid as - it doesn't seam to be able to detect md raid partitions. - For bind mounts all the subvolumes share the same uuid - """ - for i in range(storage['DISK_RETRY_ATTEMPTS']): - if not self.partprobe(): - raise DiskError(f"Could not perform partprobe on {self.device_path}") - - time.sleep(max(0.1, storage['DISK_TIMEOUTS'] * i)) + def size(self) -> Optional[float]: + return self._partition_info.size - partuuid = self._safe_part_uuid - if partuuid: - return partuuid + @property + def boot(self) -> bool: + return self._partition_info.bootable - raise DiskError(f"Could not get PARTUUID for {self.path} using 'blkid -s PARTUUID -o value {self.path}'") + @property + def partition_type(self) -> Optional[str]: + return self._partition_info.pttype + + @property + def part_uuid(self) -> str: + return self._partition_info.partuuid @property def uuid(self) -> Optional[str]: @@ -232,7 +283,7 @@ class Partition: For instance when you want to get a __repr__ of the class. """ if not self.partprobe(): - if self.block_device.info.get('TYPE') == 'iso9660': + if self.block_device.partition_type == 'iso9660': return None log(f"Could not reliably refresh PARTUUID of partition {self.device_path} due to partprobe error.", level=logging.DEBUG) @@ -240,7 +291,7 @@ class Partition: try: return SysCommand(f'blkid -s UUID -o value {self.device_path}').decode('UTF-8').strip() except SysCallError as error: - if self.block_device.info.get('TYPE') == 'iso9660': + if self.block_device.partition_type == 'iso9660': # Parent device is a Optical Disk (.iso dd'ed onto a device for instance) return None @@ -254,7 +305,7 @@ class Partition: For instance when you want to get a __repr__ of the class. """ if not self.partprobe(): - if self.block_device.info.get('TYPE') == 'iso9660': + if self.block_device.partition_type == 'iso9660': return None log(f"Could not reliably refresh PARTUUID of partition {self.device_path} due to partprobe error.", level=logging.DEBUG) @@ -262,37 +313,39 @@ class Partition: try: return SysCommand(f'blkid -s PARTUUID -o value {self.device_path}').decode('UTF-8').strip() except SysCallError as error: - if self.block_device.info.get('TYPE') == 'iso9660': + if self.block_device.partition_type == 'iso9660': # Parent device is a Optical Disk (.iso dd'ed onto a device for instance) return None log(f"Could not get PARTUUID of partition using 'blkid -s PARTUUID -o value {self.device_path}': {error}") + return self._partition_info.uuid + @property def encrypted(self) -> Union[bool, None]: return self._encrypted - @encrypted.setter - def encrypted(self, value: bool) -> None: - self._encrypted = value - @property def parent(self) -> str: return self.real_device @property def real_device(self) -> str: - for blockdevice in json.loads(SysCommand('lsblk -J').decode('UTF-8'))['blockdevices']: - if parent := self.find_parent_of(blockdevice, os.path.basename(self.device_path)): - return f"/dev/{parent}" - # raise DiskError(f'Could not find appropriate parent for encrypted partition {self}') - return self.path + output = SysCommand('lsblk -J').decode('UTF-8') + + if output: + for blockdevice in json.loads(output)['blockdevices']: + if parent := self.find_parent_of(blockdevice, os.path.basename(self.device_path)): + return f"/dev/{parent}" + return self._path + + raise DiskError('Unable to get disk information for command "lsblk -J"') @property def device_path(self) -> str: - """ for bind mounts returns the phisical path of the partition + """ for bind mounts returns the physical path of the partition """ - device_path, bind_name = split_bind_name(self.path) + device_path, bind_name = split_bind_name(self._path) return device_path @property @@ -300,38 +353,40 @@ class Partition: """ for bind mounts returns the bind name (subvolume path). Returns none if this property does not exist """ - device_path, bind_name = split_bind_name(self.path) + device_path, bind_name = split_bind_name(self._path) return bind_name @property - def subvolumes(self) -> Iterator[BtrfsSubvolume]: + def subvolumes(self) -> Iterator[BtrfsSubvolumeInfo]: from .helpers import findmnt - + def iterate_children_recursively(information): for child in information.get('children', []): if target := child.get('target'): - if subvolume := subvolume_info_from_path(pathlib.Path(target)): - yield subvolume + if child.get('fstype') == 'btrfs': + if subvolume := subvolume_info_from_path(Path(target)): + yield subvolume if child.get('children'): for subchild in iterate_children_recursively(child): yield subchild - for mountpoint in self.mount_information: - if result := findmnt(pathlib.Path(mountpoint['target'])): - for filesystem in result.get('filesystems', []): - if subvolume := subvolume_info_from_path(pathlib.Path(mountpoint['target'])): - yield subvolume + if self._partition_info.filesystem_type == 'btrfs': + for mountpoint in self._partition_info.mountpoints: + if result := findmnt(mountpoint): + for filesystem in result.get('filesystems', []): + if subvolume := subvolume_info_from_path(mountpoint): + yield subvolume - for child in iterate_children_recursively(filesystem): - yield child + for child in iterate_children_recursively(filesystem): + yield child def partprobe(self) -> bool: try: if self.block_device: return 0 == SysCommand(f'partprobe {self.block_device.device}').exit_code except SysCallError as error: - log(f"Unreliable results might be given for {self.path} due to partprobe error: {error}", level=logging.DEBUG) + log(f"Unreliable results might be given for {self._path} due to partprobe error: {error}", level=logging.DEBUG) return False @@ -343,19 +398,20 @@ class Partition: with luks2(self, storage.get('ENC_IDENTIFIER', 'ai') + 'loop', password, auto_unmount=True) as unlocked_device: return unlocked_device.filesystem except SysCallError: - return None + pass + return None def has_content(self) -> bool: - fs_type = get_filesystem_type(self.path) + fs_type = self._partition_info.filesystem_type if not fs_type or "swap" in fs_type: return False temporary_mountpoint = '/tmp/' + hashlib.md5(bytes(f"{time.time()}", 'UTF-8') + os.urandom(12)).hexdigest() - temporary_path = pathlib.Path(temporary_mountpoint) + temporary_path = Path(temporary_mountpoint) temporary_path.mkdir(parents=True, exist_ok=True) - if (handle := SysCommand(f'/usr/bin/mount {self.path} {temporary_mountpoint}')).exit_code != 0: - raise DiskError(f'Could not mount and check for content on {self.path} because: {b"".join(handle)}') + if (handle := SysCommand(f'/usr/bin/mount {self._path} {temporary_mountpoint}')).exit_code != 0: + raise DiskError(f'Could not mount and check for content on {self._path} because: {handle}') files = len(glob.glob(f"{temporary_mountpoint}/*")) iterations = 0 @@ -366,14 +422,14 @@ class Partition: return True if files > 0 else False - def encrypt(self, *args :str, **kwargs :str) -> str: + def encrypt(self, password: Optional[str] = None) -> str: """ A wrapper function for luks2() instances and the .encrypt() method of that instance. """ from ..luks import luks2 handle = luks2(self, None, None) - return handle.encrypt(self, *args, **kwargs) + return handle.encrypt(self, password=password) def format(self, filesystem :Optional[str] = None, path :Optional[str] = None, log_formatting :bool = True, options :List[str] = [], retry :bool = True) -> bool: """ @@ -381,17 +437,17 @@ class Partition: the formatting functionality and in essence the support for the given filesystem. """ if filesystem is None: - filesystem = self.filesystem + filesystem = self._partition_info.filesystem_type if path is None: - path = self.path + path = self._path # This converts from fat32 -> vfat to unify filesystem names filesystem = get_mount_fs_type(filesystem) # To avoid "unable to open /dev/x: No such file or directory" start_wait = time.time() - while pathlib.Path(path).exists() is False and time.time() - start_wait < 10: + while Path(path).exists() is False and time.time() - start_wait < 10: time.sleep(0.025) if log_formatting: @@ -401,57 +457,57 @@ class Partition: if filesystem == 'btrfs': options = ['-f'] + options - if 'UUID:' not in (mkfs := SysCommand(f"/usr/bin/mkfs.btrfs {' '.join(options)} {path}").decode('UTF-8')): + mkfs = SysCommand(f"/usr/bin/mkfs.btrfs {' '.join(options)} {path}").decode('UTF-8') + if mkfs and 'UUID:' not in mkfs: raise DiskError(f'Could not format {path} with {filesystem} because: {mkfs}') - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem elif filesystem == 'vfat': options = ['-F32'] + options - + log(f"/usr/bin/mkfs.vfat {' '.join(options)} {path}") if (handle := SysCommand(f"/usr/bin/mkfs.vfat {' '.join(options)} {path}")).exit_code != 0: raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem elif filesystem == 'ext4': options = ['-F'] + options if (handle := SysCommand(f"/usr/bin/mkfs.ext4 {' '.join(options)} {path}")).exit_code != 0: raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem elif filesystem == 'ext2': options = ['-F'] + options if (handle := SysCommand(f"/usr/bin/mkfs.ext2 {' '.join(options)} {path}")).exit_code != 0: - raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') - self.filesystem = 'ext2' - + raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") + self._partition_info.filesystem_type = 'ext2' elif filesystem == 'xfs': options = ['-f'] + options if (handle := SysCommand(f"/usr/bin/mkfs.xfs {' '.join(options)} {path}")).exit_code != 0: raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem elif filesystem == 'f2fs': options = ['-f'] + options if (handle := SysCommand(f"/usr/bin/mkfs.f2fs {' '.join(options)} {path}")).exit_code != 0: raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem elif filesystem == 'ntfs3': options = ['-f'] + options if (handle := SysCommand(f"/usr/bin/mkfs.ntfs -Q {' '.join(options)} {path}")).exit_code != 0: raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}") - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem elif filesystem == 'crypto_LUKS': # from ..luks import luks2 # encrypted_partition = luks2(self, None, None) # encrypted_partition.format(path) - self.filesystem = filesystem + self._partition_info.filesystem_type = filesystem else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") @@ -460,13 +516,13 @@ class Partition: if retry is True: log(f"Retrying in {storage.get('DISK_TIMEOUTS', 1)} seconds.", level=logging.WARNING, fg="orange") time.sleep(storage.get('DISK_TIMEOUTS', 1)) - + return self.format(filesystem, path, log_formatting, options, retry=False) if get_filesystem_type(path) == 'crypto_LUKS' or get_filesystem_type(self.real_device) == 'crypto_LUKS': - self.encrypted = True + self._encrypted = True else: - self.encrypted = False + self._encrypted = False return True @@ -478,18 +534,18 @@ class Partition: if parent := self.find_parent_of(child, name, parent=data['name']): return parent + return None + def mount(self, target :str, fs :Optional[str] = None, options :str = '') -> bool: - if not self.mountpoint: + if not self._partition_info.get_first_mountpoint(): log(f'Mounting {self} to {target}', level=logging.INFO) if not fs: - if not self.filesystem: - raise DiskError(f'Need to format (or define) the filesystem on {self} before mounting.') - fs = self.filesystem + fs = self._partition_info.filesystem_type fs_type = get_mount_fs_type(fs) - pathlib.Path(target).mkdir(parents=True, exist_ok=True) + Path(target).mkdir(parents=True, exist_ok=True) if self.bind_name: device_path = self.device_path @@ -499,7 +555,7 @@ class Partition: else: options = f"subvol={self.bind_name}" else: - device_path = self.path + device_path = self._path try: if options: mnt_handle = SysCommand(f"/usr/bin/mount -t {fs_type} -o {options} {device_path} {target}") @@ -508,7 +564,7 @@ class Partition: # TODO: Should be redundant to check for exit_code if mnt_handle.exit_code != 0: - raise DiskError(f"Could not mount {self.path} to {target} using options {options}") + raise DiskError(f"Could not mount {self._path} to {target} using options {options}") except SysCallError as err: raise err @@ -517,19 +573,17 @@ class Partition: return False def unmount(self) -> bool: - worker = SysCommand(f"/usr/bin/umount {self.path}") + worker = SysCommand(f"/usr/bin/umount {self._path}") + exit_code = worker.exit_code # Without to much research, it seams that low error codes are errors. # And above 8k is indicators such as "/dev/x not mounted.". # So anything in between 0 and 8k are errors (?). - if 0 < worker.exit_code < 8000: - raise SysCallError(f"Could not unmount {self.path} properly: {worker}", exit_code=worker.exit_code) + if exit_code and 0 < exit_code < 8000: + raise SysCallError(f"Could not unmount {self._path} properly: {worker}", exit_code=exit_code) return True - def umount(self) -> bool: - return self.unmount() - def filesystem_supported(self) -> bool: """ The support for a filesystem (this partition) is tested by calling @@ -538,7 +592,7 @@ class Partition: 2. UnknownFilesystemFormat that indicates that we don't support the given filesystem type """ try: - self.format(self.filesystem, '/dev/null', log_formatting=False, allow_formatting=True) + self.format(self._partition_info.filesystem_type, '/dev/null', log_formatting=False) except (SysCallError, DiskError): pass # We supported it, but /dev/null is not formattable as expected so the mkfs call exited with an error code except UnknownFilesystemFormat as err: diff --git a/archinstall/lib/disk/user_guides.py b/archinstall/lib/disk/user_guides.py index 5fa6bfdc..5809c073 100644 --- a/archinstall/lib/disk/user_guides.py +++ b/archinstall/lib/disk/user_guides.py @@ -3,6 +3,8 @@ import logging from typing import Optional, Dict, Any, List, TYPE_CHECKING # https://stackoverflow.com/a/39757388/929999 +from ..models.subvolume import Subvolume + if TYPE_CHECKING: from .blockdevice import BlockDevice _: Any @@ -107,17 +109,14 @@ def suggest_single_disk_layout(block_device :BlockDevice, # https://unix.stackexchange.com/questions/246976/btrfs-subvolume-uuid-clash # https://github.com/classy-giraffe/easy-arch/blob/main/easy-arch.sh layout[block_device.path]['partitions'][1]['btrfs'] = { - "subvolumes" : { - "@":"/", - "@home": "/home", - "@log": "/var/log", - "@pkg": "/var/cache/pacman/pkg", - "@.snapshots": "/.snapshots" - } + 'subvolumes': [ + Subvolume('@', '/'), + Subvolume('@home', '/home'), + Subvolume('@log', '/var/log'), + Subvolume('@pkg', '/var/cache/pacman/pkg'), + Subvolume('@.snapshots', '/.snapshots') + ] } - # else: - # pass # ... implement a guided setup - elif using_home_partition: # If we don't want to use subvolumes, # But we want to be able to re-use data between re-installs.. diff --git a/archinstall/lib/disk/validators.py b/archinstall/lib/disk/validators.py index fd1b7f33..54808886 100644 --- a/archinstall/lib/disk/validators.py +++ b/archinstall/lib/disk/validators.py @@ -7,13 +7,11 @@ def valid_parted_position(pos :str) -> bool: if pos.isdigit(): return True - if pos[-1] == '%' and pos[:-1].isdigit(): + if pos.lower().endswith('b') and pos[:-1].isdigit(): return True - if pos[-3:].lower() in ['mib', 'kib', 'b', 'tib'] and pos[:-3].replace(".", "", 1).isdigit(): - return True - - if pos[-2:].lower() in ['kb', 'mb', 'gb', 'tb'] and pos[:-2].replace(".", "", 1).isdigit(): + if any(pos.lower().endswith(size) and pos[:-len(size)].replace(".", "", 1).isdigit() + for size in ['%', 'kb', 'mb', 'gb', 'tb', 'kib', 'mib', 'gib', 'tib']): return True return False diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index a16faa3f..a66e4e04 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -1,4 +1,7 @@ -from typing import Optional +from typing import Optional, TYPE_CHECKING + +if TYPE_CHECKING: + from .general import SysCommandWorker class RequirementError(BaseException): pass @@ -17,10 +20,11 @@ class ProfileError(BaseException): class SysCallError(BaseException): - def __init__(self, message :str, exit_code :Optional[int] = None) -> None: + def __init__(self, message :str, exit_code :Optional[int] = None, worker :Optional['SysCommandWorker'] = None) -> None: super(SysCallError, self).__init__(message) self.message = message self.exit_code = exit_code + self.worker = worker class PermissionError(BaseException): diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index b99e4a45..d76b7036 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -6,12 +6,14 @@ import os import secrets import shlex import subprocess +import stat import string import sys import time import re import urllib.parse import urllib.request +import urllib.error import pathlib from datetime import datetime, date from typing import Callable, Optional, Dict, Any, List, Union, Iterator, TYPE_CHECKING @@ -37,7 +39,7 @@ else: def unregister(self, fileno :int, *args :List[Any], **kwargs :Dict[str, Any]) -> None: try: - del(self.monitoring[fileno]) + del(self.monitoring[fileno]) # noqa: E275 except: pass @@ -207,7 +209,7 @@ class SysCommandWorker: self.cmd = cmd self.callbacks = callbacks self.peak_output = peak_output - # define the standard locale for command outputs. For now the C ascii one. Can be overriden + # define the standard locale for command outputs. For now the C ascii one. Can be overridden self.environment_vars = {**storage.get('CMD_LOCALE',{}),**environment_vars} self.logfile = logfile self.working_directory = working_directory @@ -270,7 +272,7 @@ class SysCommandWorker: log(args[1], level=logging.DEBUG, fg='red') if self.exit_code != 0: - raise SysCallError(f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {self._trace_log[-500:]}", self.exit_code) + raise SysCallError(f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {self._trace_log[-500:]}", self.exit_code, worker=self) def is_alive(self) -> bool: self.poll() @@ -312,9 +314,18 @@ class SysCommandWorker: except UnicodeDecodeError: return False - with open(f"{storage['LOG_PATH']}/cmd_output.txt", "a") as peak_output_log: + peak_logfile = pathlib.Path(f"{storage['LOG_PATH']}/cmd_output.txt") + + change_perm = False + if peak_logfile.exists() is False: + change_perm = True + + with peak_logfile.open("a") as peak_output_log: peak_output_log.write(output) + if change_perm: + os.chmod(str(peak_logfile), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) + sys.stdout.write(str(output)) sys.stdout.flush() @@ -354,16 +365,24 @@ class SysCommandWorker: # Note: If for any reason, we get a Python exception between here # and until os.close(), the traceback will get locked inside # stdout of the child_fd object. `os.read(self.child_fd, 8192)` is the - # only way to get the traceback without loosing it. + # only way to get the traceback without losing it. self.pid, self.child_fd = pty.fork() # https://stackoverflow.com/questions/4022600/python-pty-fork-how-does-it-work if not self.pid: + history_logfile = pathlib.Path(f"{storage['LOG_PATH']}/cmd_history.txt") try: + change_perm = False + if history_logfile.exists() is False: + change_perm = True + try: - with open(f"{storage['LOG_PATH']}/cmd_history.txt", "a") as cmd_log: + with history_logfile.open("a") as cmd_log: cmd_log.write(f"{self.cmd}\n") + + if change_perm: + os.chmod(str(history_logfile), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) except PermissionError: pass @@ -443,7 +462,7 @@ class SysCommand: def __repr__(self, *args :List[Any], **kwargs :Dict[str, Any]) -> str: if self.session: - return self.session._trace_log.decode('UTF-8') + return self.session._trace_log.decode('UTF-8', errors='backslashreplace') return '' def __json__(self) -> Dict[str, Union[str, bool, List[str], Dict[str, Any], Optional[bool], Optional[Dict[str, Any]]]]: @@ -547,9 +566,13 @@ def json_stream_to_structure(configuration_identifier : str, stream :str, target parsed_url = urllib.parse.urlparse(stream) - if parsed_url.scheme: # The stream is in fact a URL that should be grabed - with urllib.request.urlopen(urllib.request.Request(stream, headers={'User-Agent': 'ArchInstall'})) as response: - target.update(json.loads(response.read())) + if parsed_url.scheme: # The stream is in fact a URL that should be grabbed + try: + with urllib.request.urlopen(urllib.request.Request(stream, headers={'User-Agent': 'ArchInstall'})) as response: + target.update(json.loads(response.read())) + except urllib.error.HTTPError as error: + log(f"Could not load {configuration_identifier} via {parsed_url} due to: {error}", level=logging.ERROR, fg="red") + return False else: if pathlib.Path(stream).exists(): try: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index b2cd6306..1270959e 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -24,6 +24,7 @@ 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 if TYPE_CHECKING: _: Any @@ -158,8 +159,6 @@ class Installer: print(_(" Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues")) raise args[1] - self.genfstab() - if not (missing_steps := self.post_install_check()): self.log('Installation completed without any errors. You may now reboot.', fg='green', level=logging.INFO) self.sync_log_to_install_medium() @@ -195,7 +194,7 @@ class Installer: return True def _create_keyfile(self,luks_handle , partition :dict, password :str): - """ roiutine to create keyfiles, so it can be moved elsewere + """ roiutine to create keyfiles, so it can be moved elsewhere """ if partition.get('generate-encryption-key-file'): if not (cryptkey_dir := pathlib.Path(f"{self.target}/etc/cryptsetup-keys.d")).exists(): @@ -220,7 +219,7 @@ class Installer: """ if partition.get("mountpoint") is None: if (sub_list := partition.get("btrfs",{}).get('subvolumes',{})): - for mountpoint in [sub_list[subvolume] if isinstance(sub_list[subvolume],str) else sub_list[subvolume].get("mountpoint") for subvolume in sub_list if sub_list[subvolume]]: + for mountpoint in [sub_list[subvolume].get("mountpoint") if isinstance(subvolume, dict) else subvolume.mountpoint for subvolume in sub_list]: if mountpoint == '/': return True return False @@ -247,16 +246,17 @@ class Installer: # we manage the encrypted partititons for partition in [entry for entry in list_part if entry.get('encrypted', False)]: # open the luks device and all associate stuff - if not (password := partition.get('!password', None)): - raise RequirementError(f"Missing partition {partition['device_instance'].path} encryption password in layout: {partition}") - 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}" + 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]) + if partition.get('generate-encryption-key-file', False) and not self._has_root(partition): + list_luks_handles.append([luks_handle, partition, password]) # this way all the requesrs will be to the dm_crypt device and not to the physical partition partition['device_instance'] = unlocked_device @@ -265,47 +265,25 @@ class Installer: hsm_device_path = storage['arguments']['HSM'] fido2_enroll(hsm_device_path, partition['device_instance'], password) - # we manage the btrfs partitions - if any(btrfs_subvolumes := [entry for entry in list_part if entry.get('btrfs', {}).get('subvolumes', {})]): - for partition in btrfs_subvolumes: - if mount_options := ','.join(partition.get('filesystem',{}).get('mount_options',[])): - self.mount(partition['device_instance'], "/", options=mount_options) - else: - self.mount(partition['device_instance'], "/") - - setup_subvolumes( - installation=self, - partition_dict=partition - ) + btrfs_subvolumes = [entry for entry in list_part if entry.get('btrfs', {}).get('subvolumes', [])] - partition['device_instance'].unmount() + for partition in btrfs_subvolumes: + device_instance = partition['device_instance'] + mount_options = partition.get('filesystem', {}).get('mount_options', []) + self.mount(device_instance, "/", options=','.join(mount_options)) + setup_subvolumes(installation=self, partition_dict=partition) + device_instance.unmount() # We then handle any special cases, such as btrfs - if any(btrfs_subvolumes := [entry for entry in list_part if entry.get('btrfs', {}).get('subvolumes', {})]): - for partition_information in btrfs_subvolumes: - for name, mountpoint in sorted(partition_information['btrfs']['subvolumes'].items(), key=lambda item: item[1]): - btrfs_subvolume_information = {} - - match mountpoint: - case str(): # backwards-compatability - btrfs_subvolume_information['mountpoint'] = mountpoint - btrfs_subvolume_information['options'] = [] - case dict(): - btrfs_subvolume_information['mountpoint'] = mountpoint.get('mountpoint', None) - btrfs_subvolume_information['options'] = mountpoint.get('options', []) - case _: - continue - - if mountpoint_parsed := btrfs_subvolume_information.get('mountpoint'): - # We cache the mount call for later - mount_queue[mountpoint_parsed] = lambda device=partition_information['device_instance'], \ - name=name, \ - subvolume_information=btrfs_subvolume_information: mount_subvolume( - installation=self, - device=device, - name=name, - subvolume_information=subvolume_information - ) + for partition in btrfs_subvolumes: + subvolumes: List[Subvolume] = partition['btrfs']['subvolumes'] + for subvolume in sorted(subvolumes, key=lambda item: item.mountpoint): + # We cache the mount call for later + mount_queue[subvolume.mountpoint] = lambda sub_vol=subvolume, device=partition['device_instance']: mount_subvolume( + installation=self, + device=device, + subvolume=sub_vol + ) # We mount ordinary partitions, and we sort them by the mountpoint for partition in sorted([entry for entry in list_part if entry.get('mountpoint', False)], key=lambda part: part['mountpoint']): @@ -348,7 +326,7 @@ class Installer: def enable_multilib_repository(self): # Set up a regular expression pattern of a commented line containing 'multilib' within [] - pattern = re.compile("^#\\[.*multilib.*\\]$") + pattern = re.compile(r"^#\s*\[multilib\]$") # This is used to track if the previous line is a match, so we end up uncommenting the line after the block. matched = False @@ -413,7 +391,7 @@ class Installer: try: run_pacman('-Syy', default_cmd='/usr/bin/pacman') except SysCallError as error: - self.log(f'Could not sync a new package databse: {error}', level=logging.ERROR, fg="red") + self.log(f'Could not sync a new package database: {error}', level=logging.ERROR, fg="red") if storage['arguments'].get('silent', False) is False: if input('Would you like to re-try this download? (Y/n): ').lower().strip() in ('', 'y'): @@ -454,7 +432,8 @@ class Installer: for plugin in plugins.values(): if hasattr(plugin, 'on_genfstab'): - plugin.on_genfstab(self) + if plugin.on_genfstab(self) is True: + break return True @@ -466,10 +445,27 @@ class Installer: if not len(locale): return True + modifier = '' + + # This is a temporary patch to fix #1200 + if '.' in locale: + locale, potential_encoding = locale.split('.', 1) + + # Override encoding if encoding is set to the default parameter + # and the "found" encoding differs. + if encoding == 'UTF-8' and encoding != potential_encoding: + encoding = potential_encoding + + # Make sure we extract the modifier, that way we can put it in if needed. + if '@' in locale: + locale, modifier = locale.split('@', 1) + modifier = f"@{modifier}" + # - End patch + with open(f'{self.target}/etc/locale.gen', 'a') as fh: - fh.write(f'{locale}.{encoding} {encoding}\n') + fh.write(f'{locale}.{encoding}{modifier} {encoding}\n') with open(f'{self.target}/etc/locale.conf', 'w') as fh: - fh.write(f'LANG={locale}.{encoding}\n') + fh.write(f'LANG={locale}.{encoding}{modifier}\n') return True if SysCommand(f'/usr/bin/arch-chroot {self.target} locale-gen').exit_code == 0 else False @@ -654,7 +650,7 @@ class Installer: mkinit.write(f"BINARIES=({' '.join(self.BINARIES)})\n") mkinit.write(f"FILES=({' '.join(self.FILES)})\n") - if not storage['arguments']['HSM']: + if not storage['arguments'].get('HSM'): # 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. @@ -696,7 +692,7 @@ class Installer: self.HOOKS.remove('fsck') if self.detect_encryption(partition): - if storage['arguments']['HSM']: + if storage['arguments'].get('HSM'): # Required bby mkinitcpio to add support for fido2-device options self.pacstrap('libfido2') @@ -728,7 +724,7 @@ class Installer: self.log("The multilib flag is set. This system will be installed with the multilib repository enabled.") self.enable_multilib_repository() else: - self.log("The testing flag is not set. This system will be installed without testing repositories enabled.") + self.log("The multilib flag is not set. This system will be installed without multilib repositories enabled.") if testing: self.log("The testing flag is set. This system will be installed with testing repositories enabled.") @@ -760,7 +756,7 @@ class Installer: # TODO: Use python functions for this SysCommand(f'/usr/bin/arch-chroot {self.target} chmod 700 /root') - if storage['arguments']['HSM']: + if storage['arguments'].get('HSM'): # 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. @@ -872,7 +868,7 @@ class Installer: options_entry = f'rw intel_pstate=no_hwp {" ".join(self.KERNEL_PARAMS)}\n' for subvolume in root_partition.subvolumes: - if subvolume.root is True: + if subvolume.root is True and subvolume.name != '<FS_TREE>': options_entry = f"rootflags=subvol={subvolume.name} " + options_entry # Zswap should be disabled when using zram. @@ -888,7 +884,7 @@ class Installer: kernel_options = f"options" - if storage['arguments']['HSM']: + if storage['arguments'].get('HSM'): # 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: @@ -1022,10 +1018,9 @@ class Installer: boot_partition = None root_partition = None for partition in self.partitions: - print(partition, [partition.mountpoint], [self.target]) - if partition.mountpoint == self.target / 'boot': + if self.target / 'boot' in partition.mountpoints: boot_partition = partition - elif partition.mountpoint == self.target: + elif self.target in partition.mountpoints: root_partition = partition if boot_partition is None or root_partition is None: @@ -1154,7 +1149,8 @@ class Installer: return SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\"").exit_code == 0 def chown(self, owner :str, path :str, options :List[str] = []) -> bool: - return SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c 'chown {' '.join(options)} {owner} {path}").exit_code == 0 + cleaned_path = path.replace('\'', '\\\'') + return SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c 'chown {' '.join(options)} {owner} {cleaned_path}'").exit_code == 0 def create_file(self, filename :str, owner :Optional[str] = None) -> InstallationFile: return InstallationFile(self, filename, owner) diff --git a/archinstall/lib/locale_helpers.py b/archinstall/lib/locale_helpers.py index b48c3bc4..5580fa91 100644 --- a/archinstall/lib/locale_helpers.py +++ b/archinstall/lib/locale_helpers.py @@ -20,7 +20,7 @@ def list_locales() -> List[str]: entries.reverse() for entry in entries: - text = entry[1:].strip() + text = entry.replace('#', '').strip() if text == '': break locales.append(text) diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index ac480b11..7e4534d8 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -22,9 +22,9 @@ from .disk.btrfs import BTRFSPartition class luks2: def __init__(self, - partition :Partition, - mountpoint :str, - password :str, + partition: Partition, + mountpoint: Optional[str], + password: Optional[str], key_file :Optional[str] = None, auto_unmount :bool = False, *args :str, diff --git a/archinstall/lib/menu/global_menu.py b/archinstall/lib/menu/global_menu.py index 5cb27cab..d1bec189 100644 --- a/archinstall/lib/menu/global_menu.py +++ b/archinstall/lib/menu/global_menu.py @@ -3,38 +3,37 @@ from __future__ import annotations from typing import Any, List, Optional, Union, Dict, TYPE_CHECKING import archinstall - -from ..menu import Menu -from ..menu.selection_menu import Selector, GeneralMenu +from ..disk import encrypted_partitions from ..general import SysCommand, secret from ..hardware import has_uefi +from ..menu import Menu +from ..menu.selection_menu import Selector, GeneralMenu from ..models import NetworkConfiguration -from ..storage import storage +from ..models.users import User +from ..output import FormattedOutput from ..profiles import is_desktop_profile, Profile -from ..disk import encrypted_partitions - -from ..user_interaction import get_password, ask_for_a_timezone, save_config -from ..user_interaction import ask_ntp -from ..user_interaction import ask_for_swap +from ..storage import storage +from ..user_interaction import add_number_of_parrallel_downloads +from ..user_interaction import ask_additional_packages_to_install +from ..user_interaction import ask_for_additional_users +from ..user_interaction import ask_for_audio_selection from ..user_interaction import ask_for_bootloader +from ..user_interaction import ask_for_swap from ..user_interaction import ask_hostname -from ..user_interaction import ask_for_audio_selection -from ..user_interaction import ask_additional_packages_to_install +from ..user_interaction import ask_ntp from ..user_interaction import ask_to_configure_network -from ..user_interaction import ask_for_additional_users -from ..user_interaction import select_language -from ..user_interaction import select_mirror_regions -from ..user_interaction import select_locale_lang -from ..user_interaction import select_locale_enc +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_kernel 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 +from ..user_interaction import select_locale_enc +from ..user_interaction import select_locale_lang +from ..user_interaction import select_mirror_regions from ..user_interaction import select_profile -from ..user_interaction import select_additional_repositories -from ..models.users import User from ..user_interaction.partitioning_conf import current_partition_layout -from ..output import FormattedOutput if TYPE_CHECKING: _: Any @@ -42,6 +41,7 @@ if TYPE_CHECKING: class GlobalMenu(GeneralMenu): def __init__(self,data_store): + self._disk_check = True super().__init__(data_store=data_store, auto_cursor=True, preview_size=0.3) def _setup_selection_menu_options(self): @@ -50,7 +50,8 @@ class GlobalMenu(GeneralMenu): Selector( _('Archinstall language'), lambda x: self._select_archinstall_language(x), - default='English') + display_func=lambda x: x.display_name, + default=self.translation_handler.get_language_by_abbr('en')) self._menu_options['keyboard-layout'] = \ Selector( _('Keyboard layout'), @@ -143,6 +144,15 @@ class GlobalMenu(GeneralMenu): display_func=lambda x: x if x else 'None', default=None ) + + self._menu_options['parallel downloads'] = \ + Selector( + _('Parallel Downloads'), + add_number_of_parrallel_downloads, + display_func=lambda x: x if x else '0', + default=0 + ) + self._menu_options['kernels'] = \ Selector( _('Kernels'), @@ -163,7 +173,8 @@ class GlobalMenu(GeneralMenu): Selector( _('Network configuration'), ask_to_configure_network, - display_func=lambda x: self._prev_network_configuration(x), + display_func=lambda x: self._display_network_conf(x), + preview_func=self._prev_network_config, default={}) self._menu_options['timezone'] = \ Selector( @@ -204,14 +215,21 @@ class GlobalMenu(GeneralMenu): # 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']: - for partition_index in select_encrypted_partitions( - title="Select which partitions to encrypt:", - partitions=storage['arguments']['disk_layouts'][blockdevice]['partitions'] - ): - - partition = storage['arguments']['disk_layouts'][blockdevice]['partitions'][partition_index] - partition['encrypted'] = True - partition['!password'] = storage['arguments']['!encryption-password'] + 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()) @@ -219,21 +237,28 @@ class GlobalMenu(GeneralMenu): return _('Install ({} config(s) missing)').format(missing) return _('Install') - def _prev_network_configuration(self, cur_value: Union[NetworkConfiguration, List[NetworkConfiguration]]) -> str: + def _display_network_conf(self, cur_value: Union[NetworkConfiguration, List[NetworkConfiguration]]) -> str: if not cur_value: return _('Not configured, unavailable unless setup manually') else: if isinstance(cur_value, list): - ifaces = [x.iface for x in cur_value] - return f'Configured ifaces: {ifaces}' + return str(_('Configured {} interfaces')).format(len(cur_value)) else: return str(cur_value) + def _prev_network_config(self) -> Optional[str]: + selector = self._menu_options['nic'] + if selector.has_selection(): + ifaces = selector.current_selection + if isinstance(ifaces, list): + return FormattedOutput.as_table(ifaces) + return None + def _prev_harddrives(self) -> Optional[str]: selector = self._menu_options['harddrives'] if selector.has_selection(): drives = selector.current_selection - return '\n\n'.join([d.display_info for d in drives]) + return FormattedOutput.as_table(drives) return None def _prev_disk_layouts(self) -> Optional[str]: @@ -288,11 +313,12 @@ class GlobalMenu(GeneralMenu): missing += ['Hostname'] if not check('!root-password') and not has_superuser(): missing += [str(_('Either root-password or at least 1 user with sudo privileges must be specified'))] - if not check('harddrives'): - missing += ['Hard drives'] - if check('harddrives'): - if not self._menu_options['harddrives'].is_empty() and not check('disk_layouts'): - missing += ['Disk layout'] + if self._disk_check: + if not check('harddrives'): + missing += [str(_('Drive(s)'))] + if check('harddrives'): + if not self._menu_options['harddrives'].is_empty() and not check('disk_layouts'): + missing += [str(_('Disk layout'))] return missing @@ -318,22 +344,26 @@ class GlobalMenu(GeneralMenu): def _select_harddrives(self, old_harddrives : list) -> List: harddrives = select_harddrives(old_harddrives) - if len(harddrives) == 0: - prompt = _( - "You decided to skip harddrive selection\nand 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?" - ).format(storage['MOUNT_POINT']) + if harddrives is not None: + if len(harddrives) == 0: + prompt = _( + "You decided to skip harddrive selection\nand 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?" + ).format(storage['MOUNT_POINT']) - choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), skip=False).run() + choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), skip=False).run() - if choice.value == Menu.no(): - return self._select_harddrives(old_harddrives) + if choice.value == Menu.no(): + self._disk_check = True + return self._select_harddrives(old_harddrives) + else: + self._disk_check = False - # in case the harddrives got changed we have to reset the disk layout as well - if old_harddrives != harddrives: - self._menu_options['disk_layouts'].set_current_selection(None) - storage['arguments']['disk_layouts'] = {} + # in case the harddrives got changed we have to reset the disk layout as well + if old_harddrives != harddrives: + self._menu_options['disk_layouts'].set_current_selection(None) + storage['arguments']['disk_layouts'] = {} return harddrives diff --git a/archinstall/lib/menu/list_manager.py b/archinstall/lib/menu/list_manager.py index cb567093..ae3a6eb5 100644 --- a/archinstall/lib/menu/list_manager.py +++ b/archinstall/lib/menu/list_manager.py @@ -1,94 +1,7 @@ -#!/usr/bin/python -""" -# Purpose -ListManager is a widget based on `menu` which allows the handling of repetitive operations in a list. -Imagine you have a list and want to add/copy/edit/delete their elements. With this widget you will be shown the list -``` -Vamos alla - -Use ESC to skip - - -> uno : 1 -dos : 2 -tres : 3 -cuatro : 4 -==> -Confirm and exit -Cancel -(Press "/" to search) -``` -Once you select one of the elements of the list, you will be promted with the action to be done to the selected element -``` - -uno : 1 -dos : 2 -> tres : 3 -cuatro : 4 -==> -Confirm and exit -Cancel -(Press "/" to search) - -Select an action for < {'tres': 3} > - - -Add -Copy -Edit -Delete -> Cancel -``` -You execute the action for this element (which might or not involve user interaction) and return to the list main page -till you call one of the options `confirm and exit` which returns the modified list or `cancel` which returns the original list unchanged. -If the list is empty one action can be defined as default (usually Add). We call it **null_action** -YOu can also define a **default_action** which will appear below the separator, not tied to any element of the list. Barring explicit definition, default_action will be the null_action -``` -==> -Add -Confirm and exit -Cancel -(Press "/" to search) -``` -The default implementation can handle simple lists and a key:value dictionary. The default actions are the shown above. -A sample of basic usage is included at the end of the source. - -More sophisticaded uses can be achieved by -* changing the action list and the null_action during intialization -``` - opciones = ListManager('Vamos alla',opciones,[str(_('Add')),str(_('Delete'))],_('Add')).run() -``` -* And using following methods to overwrite/define user actions and other details: -* * `reformat`. To change the appearance of the list elements -* * `action_list`. To modify the content of the action list once an element is defined. F.i. to avoid Delete to appear for certain elements, or to add/modify action based in the value of the element. -* * `exec_action` which contains the actual code to be executed when an action is selected - -The contents in the base class of this methods serve for a very basic usage, and are to be taken as samples. Thus the best use of this class would be to subclass in your code - -``` - class ObjectList(archinstall.ListManager): - def __init__(prompt,list): - self.ObjectAction = [... list of actions ...] - self.ObjectNullAction = one ObjectAction - super().__init__(prompt,list,ObjectActions,ObjectNullAction) - def reformat(self): - ... beautfy the output of the list - def action_list(self): - ... if you need some changes to the action list based on self.target - def exec_action(self): - if self.action == self.ObjectAction[0]: - performFirstAction(self.target, ...) - - ... - resultList = ObjectList(prompt,originallist).run() -``` - -""" import copy from os import system -from typing import Union, Any, TYPE_CHECKING, Dict, Optional +from typing import Any, TYPE_CHECKING, Dict, Optional, Tuple, List -from .text_input import TextInput from .menu import Menu if TYPE_CHECKING: @@ -98,199 +11,132 @@ if TYPE_CHECKING: class ListManager: def __init__( self, - prompt :str, - base_list :Union[list,dict] , - base_actions :list = None, - null_action :str = None, - default_action :Union[str,list] = None, - header :Union[str,list] = None): + prompt: str, + entries: List[Any], + base_actions: List[str], + sub_menu_actions: List[str] + ): """ - param :prompt Text which will appear at the header + :param prompt: Text which will appear at the header type param: string | DeferredTranslation - param :base:_list list/dict of option to be shown / mainpulated - type param: list | dict - - param base_actions an alternate list of actions to the items of the object + :param entries: list/dict of option to be shown / manipulated type param: list - param: null_action action which will be taken (if any) when base_list is empty - type param: string - - param: default_action action which will be presented at the bottom of the list. Shouldn't need a target. If not present, null_action is set there. - Both Null and Default actions can be defined outside the base_actions list, as long as they are launched in exec_action - type param: string or list + :param base_actions: list of actions that is displayed in the main list manager, + usually global actions such as 'Add...' + type param: list - param: header one or more header lines for the list - type param: string or list + :param sub_menu_actions: list of actions available for a chosen entry + type param: list """ + self._original_data = copy.deepcopy(entries) + self._data = copy.deepcopy(entries) explainer = str(_('\n Choose an object from the list, and select one of the available actions for it to execute')) self._prompt = prompt + explainer if prompt else explainer - self._null_action = str(null_action) if null_action else None + self._separator = '' + self._confirm_action = str(_('Confirm and exit')) + self._cancel_action = str(_('Cancel')) - if not default_action: - self._default_action = [self._null_action] - elif isinstance(default_action,(list,tuple)): - self._default_action = default_action - else: - self._default_action = [str(default_action),] + self._terminate_actions = [self._confirm_action, self._cancel_action] + self._base_actions = base_actions + self._sub_menu_actions = sub_menu_actions - self.header = header if header else None - self.cancel_action = str(_('Cancel')) - self.confirm_action = str(_('Confirm and exit')) - self.separator = '' - self.bottom_list = [self.confirm_action,self.cancel_action] - self.bottom_item = [self.cancel_action] - self.base_actions = base_actions if base_actions else [str(_('Add')),str(_('Copy')),str(_('Edit')),str(_('Delete'))] - self._original_data = copy.deepcopy(base_list) - self._data = copy.deepcopy(base_list) # as refs, changes are immediate - # default values for the null case - self.target: Optional[Any] = None - self.action = self._null_action + self._last_choice = None - if len(self._data) == 0 and self._null_action: - self._data = self.exec_action(self._data) + @property + def last_choice(self): + return self._last_choice def run(self): while True: # this will return a dictionary with the key as the menu entry to be displayed # and the value is the original value from the self._data container data_formatted = self.reformat(self._data) - options = list(data_formatted.keys()) - options.append(self.separator) - - if self._default_action: - options += self._default_action - - options += self.bottom_list + options, header = self._prepare_selection(data_formatted) system('clear') - target = Menu( + choice = Menu( self._prompt, options, sort=False, clear_screen=False, clear_menu_on_exit=False, - header=self.header, + header=header, skip_empty_entries=True, - skip=False + skip=False, + show_search_hint=False ).run() - if not target.value or target.value in self.bottom_list: - self.action = target + if choice.value in self._base_actions: + self._data = self.handle_action(choice.value, None, self._data) + elif choice.value in self._terminate_actions: break + else: # an entry of the existing selection was choosen + selected_entry = data_formatted[choice.value] + self._run_actions_on_entry(selected_entry) - if target.value and target.value in self._default_action: - self.action = target.value - self.target = None - self._data = self.exec_action(self._data) - continue - - if isinstance(self._data,dict): - data_key = data_formatted[target.value] - key = self._data[data_key] - self.target = {data_key: key} - elif isinstance(self._data, list): - self.target = [d for d in self._data if d == data_formatted[target.value]][0] - else: - self.target = self._data[data_formatted[target.value]] - - # Possible enhacement. If run_actions returns false a message line indicating the failure - self.run_actions(target.value) - - if target.value == self.cancel_action: # TODO dubious + self._last_choice = choice + if choice.value == self._cancel_action: return self._original_data # return the original list else: return self._data - def run_actions(self,prompt_data=None): - options = self.action_list() + self.bottom_item - prompt = _("Select an action for < {} >").format(prompt_data if prompt_data else self.target) + def _prepare_selection(self, data_formatted: Dict[str, Any]) -> Tuple[List[str], str]: + # header rows are mapped to None so make sure + # to exclude those from the selectable data + options: List[str] = [key for key, val in data_formatted.items() if val is not None] + header = '' + + if len(options) > 0: + table_header = [key for key, val in data_formatted.items() if val is None] + header = '\n'.join(table_header) + + if len(options) > 0: + options.append(self._separator) + + options += self._base_actions + options += self._terminate_actions + + return options, header + + def _run_actions_on_entry(self, entry: Any): + 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) + choice = Menu( prompt, options, sort=False, clear_screen=False, clear_menu_on_exit=False, - preset_values=self.bottom_item, show_search_hint=False ).run() - self.action = choice.value + if choice.value and choice.value != self._cancel_action: + self._data = self.handle_action(choice.value, entry, self._data) - if self.action and self.action != self.cancel_action: - self._data = self.exec_action(self._data) + def selected_action_display(self, selection: Any) -> str: + # this will return the value to be displayed in the + # "Select an action for '{}'" string + raise NotImplementedError('Please implement me in the child class') - """ - The following methods are expected to be overwritten by the user if the needs of the list are beyond the simple case - """ + def reformat(self, data: List[Any]) -> Dict[str, Any]: + # this should return a dictionary of display string to actual data entry + # mapping; if the value for a given display string is None it will be used + # in the header value (useful when displaying tables) + raise NotImplementedError('Please implement me in the child class') - def reformat(self, data: Any) -> Dict[str, Any]: - """ - method to get the data in a format suitable to be shown - It is executed once for run loop and processes the whole self._data structure - """ - if isinstance(data,dict): - return {f'{k}: {v}': k for k, v in data.items()} - else: - return {str(k): k for k in data} - - def action_list(self): - """ - can define alternate action list or customize the list for each item. - Executed after any item is selected, contained in self.target - """ - return self.base_actions - - def exec_action(self, data: Any): - """ - what's executed one an item (self.target) and one action (self.action) is selected. - Should be overwritten by the user - The result is expected to update self._data in this routine, else it is ignored - The basic code is useful for simple lists and dictionaries (key:value pairs, both strings) - """ - # TODO guarantee unicity - if isinstance(self._data,list): - if self.action == str(_('Add')): - self.target = TextInput(_('Add: '),None).run() - self._data.append(self.target) - if self.action == str(_('Copy')): - while True: - target = TextInput(_('Copy to: '),self.target).run() - if target != self.target: - self._data.append(self.target) - break - elif self.action == str(_('Edit')): - tgt = self.target - idx = self._data.index(self.target) - result = TextInput(_('Edit: '),tgt).run() - self._data[idx] = result - elif self.action == str(_('Delete')): - del self._data[self._data.index(self.target)] - elif isinstance(self._data,dict): - # allows overwrites - if self.target: - origkey,origval = list(self.target.items())[0] - else: - origkey = None - origval = None - if self.action == str(_('Add')): - key = TextInput(_('Key: '),None).run() - value = TextInput(_('Value: '),None).run() - self._data[key] = value - if self.action == str(_('Copy')): - while True: - key = TextInput(_('Copy to new key:'),origkey).run() - if key != origkey: - self._data[key] = origval - break - elif self.action == str(_('Edit')): - value = TextInput(_('Edit {}: ').format(origkey), origval).run() - self._data[origkey] = value - elif self.action == str(_('Delete')): - del self._data[origkey] + def handle_action(self, action: Any, entry: Optional[Any], data: List[Any]) -> List[Any]: + # this function is called when a base action or + # a specific action for an entry is triggered + raise NotImplementedError('Please implement me in the child class') - return self._data + def filter_options(self, selection :Any, options :List[str]) -> List[str]: + # filter which actions to show for an specific selection + return options diff --git a/archinstall/lib/menu/menu.py b/archinstall/lib/menu/menu.py index c34814eb..112bc0ae 100644 --- a/archinstall/lib/menu/menu.py +++ b/archinstall/lib/menu/menu.py @@ -1,6 +1,7 @@ from dataclasses import dataclass from enum import Enum, auto -from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional +from os import system +from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional, Callable from archinstall.lib.menu.simple_menu import TerminalMenu @@ -51,13 +52,17 @@ class Menu(TerminalMenu): sort :bool = True, preset_values :Union[str, List[str]] = None, cursor_index : Optional[int] = None, - preview_command=None, - preview_size=0.75, - preview_title='Info', + preview_command: Optional[Callable] = None, + preview_size: float = 0.75, + preview_title: str = 'Info', header :Union[List[str],str] = None, - explode_on_interrupt :bool = False, - explode_warning :str = '', - **kwargs + raise_error_on_interrupt :bool = False, + raise_error_warning_msg :str = '', + clear_screen: bool = True, + show_search_hint: bool = True, + cycle_cursor: bool = True, + clear_menu_on_exit: bool = True, + skip_empty_entries: bool = False ): """ Creates a new menu @@ -99,10 +104,10 @@ class Menu(TerminalMenu): param header: one or more header lines for the menu type param: string or list - param explode_on_interrupt: This will explicitly handle a ctrl+c instead and return that specific state + param raise_error_on_interrupt: This will explicitly handle a ctrl+c instead and return that specific state type param: bool - param explode_warning: If explode_on_interrupt is True and this is non-empty, there will be a warning with a user confirmation displayed + param raise_error_warning_msg: If raise_error_on_interrupt is True and this is non-empty, there will be a warning with a user confirmation displayed type param: str :param kwargs : any SimpleTerminal parameter @@ -115,7 +120,7 @@ class Menu(TerminalMenu): # We check that the options are iterable. If not we abort. Else we copy them to lists # it options is a dictionary we use the values as entries of the list # if options is a string object, each character becomes an entry - # if options is a list, we implictily build a copy to mantain immutability + # if options is a list, we implictily build a copy to maintain immutability if not isinstance(p_options,Iterable): log(f"Objects of type {type(p_options)} is not iterable, and are not supported at Menu",fg="red") log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING) @@ -145,27 +150,30 @@ class Menu(TerminalMenu): self._skip = skip self._default_option = default_option self._multi = multi - self._explode_on_interrupt = explode_on_interrupt - self._explode_warning = explode_warning + self._raise_error_on_interrupt = raise_error_on_interrupt + self._raise_error_warning_msg = raise_error_warning_msg + self._preview_command = preview_command menu_title = f'\n{title}\n\n' if header: if not isinstance(header,(list,tuple)): header = [header] - header = '\n'.join(header) - menu_title += f'\n{header}\n' + menu_title += '\n'.join(header) action_info = '' if skip: - action_info += str(_("Use ESC to skip")) + action_info += str(_('ESC to skip')) - if self._explode_on_interrupt: - if len(action_info) > 0: - action_info += '\n' - action_info += str(_('Use CTRL+C to reset current selection\n\n')) + if self._raise_error_on_interrupt: + action_info += ', ' if len(action_info) > 0 else '' + action_info += str(_('CTRL+C to reset')) - menu_title += action_info + if multi: + action_info += ', ' if len(action_info) > 0 else '' + action_info += str(_('TAB to select')) + + menu_title += action_info + '\n' if default_option: # if a default value was specified we move that one @@ -178,10 +186,6 @@ class Menu(TerminalMenu): cursor = "> " main_menu_cursor_style = ("fg_cyan", "bold") main_menu_style = ("bg_blue", "fg_gray") - # defaults that can be changed up the stack - kwargs['clear_screen'] = kwargs.get('clear_screen',True) - kwargs['show_search_hint'] = kwargs.get('show_search_hint',True) - kwargs['cycle_cursor'] = kwargs.get('cycle_cursor',True) super().__init__( menu_entries=self._menu_options, @@ -195,12 +199,16 @@ class Menu(TerminalMenu): # show_search_hint=True, preselected_entries=self.preset_values, cursor_index=self.cursor_index, - preview_command=preview_command, + preview_command=lambda x: self._preview_wrapper(preview_command, x), preview_size=preview_size, preview_title=preview_title, - explode_on_interrupt=self._explode_on_interrupt, + raise_error_on_interrupt=self._raise_error_on_interrupt, multi_select_select_on_accept=False, - **kwargs, + clear_screen=clear_screen, + show_search_hint=show_search_hint, + cycle_cursor=cycle_cursor, + clear_menu_on_exit=clear_menu_on_exit, + skip_empty_entries=skip_empty_entries ) def _show(self) -> MenuSelection: @@ -228,16 +236,24 @@ class Menu(TerminalMenu): else: return MenuSelection(type_=MenuSelectionType.Esc) + def _preview_wrapper(self, preview_command: Optional[Callable], current_selection: str) -> Optional[str]: + if preview_command: + if self._default_option is not None and f'{self._default_option} {self._default_str}' == current_selection: + current_selection = self._default_option + return preview_command(current_selection) + return None + def run(self) -> MenuSelection: ret = self._show() if ret.type_ == MenuSelectionType.Ctrl_c: - if self._explode_on_interrupt and len(self._explode_warning) > 0: - response = Menu(self._explode_warning, Menu.yes_no(), skip=False).run() + 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() return ret diff --git a/archinstall/lib/menu/selection_menu.py b/archinstall/lib/menu/selection_menu.py index 57e290f1..8a08812c 100644 --- a/archinstall/lib/menu/selection_menu.py +++ b/archinstall/lib/menu/selection_menu.py @@ -8,22 +8,15 @@ from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CH from .menu import Menu, MenuSelectionType from ..locale_helpers import set_keyboard_language from ..output import log -from ..translation import Translation +from ..translationhandler import TranslationHandler, Language from ..hsm.fido import get_fido2_devices +from ..user_interaction.general_conf import select_archinstall_language + if TYPE_CHECKING: _: Any -def select_archinstall_language(preset_value: str) -> Optional[Any]: - """ - copied from user_interaction/general_conf.py as a temporary measure - """ - languages = Translation.get_available_lang() - language = Menu(_('Archinstall language'), languages, preset_values=preset_value).run() - return language.value - - class Selector: def __init__( self, @@ -190,13 +183,18 @@ class GeneralMenu: """ self._enabled_order :List[str] = [] - self._translation = Translation.load_nationalization() + self._translation_handler = TranslationHandler() self.is_context_mgr = False self._data_store = data_store if data_store is not None else {} self.auto_cursor = auto_cursor self._menu_options: Dict[str, Selector] = {} self._setup_selection_menu_options() self.preview_size = preview_size + self._last_choice = None + + @property + def last_choice(self): + return self._last_choice def __enter__(self, *args :Any, **kwargs :Any) -> GeneralMenu: self.is_context_mgr = True @@ -217,9 +215,13 @@ class GeneralMenu: self.exit_callback() + @property + def translation_handler(self) -> TranslationHandler: + return self._translation_handler + def _setup_selection_menu_options(self): """ Define the menu options. - Menu options can be defined here in a subclass or done per progam calling self.set_option() + Menu options can be defined here in a subclass or done per program calling self.set_option() """ return @@ -227,7 +229,7 @@ class GeneralMenu: """ will be called before each action in the menu """ return - def post_callback(self, selector_name :str, value :Any): + def post_callback(self, selection_name: str = None, value: Any = None): """ will be called after each action in the menu """ return True @@ -327,12 +329,16 @@ class GeneralMenu: 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()] if not self.is_context_mgr: self.__exit__() @@ -347,7 +353,7 @@ class GeneralMenu: return self.exec_option(config_name, selector) def exec_option(self, config_name :str, p_selector :Selector = None) -> bool: - """ processes the exection of a given menu entry + """ processes the execution of a given menu entry - pre process callback - selection function - post process callback @@ -461,13 +467,10 @@ class GeneralMenu: mandatory_waiting += 1 return mandatory_fields, mandatory_waiting - def _select_archinstall_language(self, preset_value: str) -> str: - language = select_archinstall_language(preset_value) - if language is not None: - self._translation.activate(language) - return language - - return preset_value + def _select_archinstall_language(self, preset_value: Language) -> Language: + language = select_archinstall_language(self.translation_handler.translated_languages, preset_value) + 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:') diff --git a/archinstall/lib/menu/simple_menu.py b/archinstall/lib/menu/simple_menu.py index 947259eb..1980e2ce 100644 --- a/archinstall/lib/menu/simple_menu.py +++ b/archinstall/lib/menu/simple_menu.py @@ -65,7 +65,7 @@ __author__ = "Ingo Meyer" __email__ = "i.meyer@fz-juelich.de" __copyright__ = "Copyright © 2021 Forschungszentrum Jülich GmbH. All rights reserved." __license__ = "MIT" -__version_info__ = (1, 4, 1) +__version_info__ = (1, 5, 0) __version__ = ".".join(map(str, __version_info__)) @@ -86,6 +86,7 @@ DEFAULT_MULTI_SELECT_SELECT_ON_ACCEPT = True DEFAULT_PREVIEW_BORDER = True DEFAULT_PREVIEW_SIZE = 0.25 DEFAULT_PREVIEW_TITLE = "preview" +DEFAULT_QUIT_KEYS = ("escape", "q") DEFAULT_SEARCH_CASE_SENSITIVE = False DEFAULT_SEARCH_HIGHLIGHT_STYLE = ("fg_black", "bg_yellow", "bold") DEFAULT_SEARCH_KEY = "/" @@ -581,6 +582,8 @@ class TerminalMenu: preview_command: Optional[Union[str, Callable[[str], str]]] = None, preview_size: float = DEFAULT_PREVIEW_SIZE, preview_title: str = DEFAULT_PREVIEW_TITLE, + quit_keys: Iterable[str] = DEFAULT_QUIT_KEYS, + raise_error_on_interrupt: bool = False, search_case_sensitive: bool = DEFAULT_SEARCH_CASE_SENSITIVE, search_highlight_style: Optional[Iterable[str]] = DEFAULT_SEARCH_HIGHLIGHT_STYLE, search_key: Optional[str] = DEFAULT_SEARCH_KEY, @@ -596,8 +599,7 @@ class TerminalMenu: status_bar: Optional[Union[str, Iterable[str], Callable[[str], str]]] = None, status_bar_below_preview: bool = DEFAULT_STATUS_BAR_BELOW_PREVIEW, status_bar_style: Optional[Iterable[str]] = DEFAULT_STATUS_BAR_STYLE, - title: Optional[Union[str, Iterable[str]]] = None, - explode_on_interrupt: bool = False + title: Optional[Union[str, Iterable[str]]] = None ): def extract_shortcuts_menu_entries_and_preview_arguments( entries: Iterable[str], @@ -716,10 +718,11 @@ class TerminalMenu: self._preview_command = preview_command self._preview_size = preview_size self._preview_title = preview_title + self._quit_keys = tuple(quit_keys) + self._raise_error_on_interrupt = raise_error_on_interrupt self._search_case_sensitive = search_case_sensitive self._search_highlight_style = tuple(search_highlight_style) if search_highlight_style is not None else () self._search_key = search_key - self._explode_on_interrupt = explode_on_interrupt self._shortcut_brackets_highlight_style = ( tuple(shortcut_brackets_highlight_style) if shortcut_brackets_highlight_style is not None else () ) @@ -787,6 +790,7 @@ class TerminalMenu: # backspace can be queried from the terminal database but is unreliable, query the terminal directly instead self._init_backspace_control_character() self._add_missing_control_characters_for_keys(self._accept_keys) + self._add_missing_control_characters_for_keys(self._quit_keys) self._init_terminal_codes() @staticmethod @@ -1477,7 +1481,7 @@ class TerminalMenu: "menu_down": set(("down", "ctrl-j", "j")), "accept": set(self._accept_keys), "multi_select": set(self._multi_select_keys), - "quit": set(("escape", "q")), + "quit": set(self._quit_keys), "search_start": set((self._search_key,)), "backspace": set(("backspace",)), } # type: Dict[str, Set[Optional[str]]] @@ -1541,7 +1545,7 @@ class TerminalMenu: # `search_start` key self._search.search_text += next_key except KeyboardInterrupt as e: - if self._explode_on_interrupt: + if self._raise_error_on_interrupt: raise e menu_was_interrupted = True finally: @@ -1846,12 +1850,6 @@ def get_argumentparser() -> argparse.ArgumentParser: ) parser.add_argument("-t", "--title", action="store", dest="title", help="menu title") parser.add_argument( - "--explode-on-interrupt", - action="store_true", - dest="explode_on_interrupt", - help="Instead of quitting the menu, this will raise the KeyboardInterrupt Exception", - ) - parser.add_argument( "-V", "--version", action="store_true", dest="print_version", help="print the version number and exit" ) parser.add_argument("entries", action="store", nargs="*", help="the menu entries to show") @@ -1981,7 +1979,6 @@ def main() -> None: status_bar_below_preview=args.status_bar_below_preview, status_bar_style=args.status_bar_style, title=args.title, - explode_on_interrupt=args.explode_on_interrupt, ) except (InvalidParameterCombinationError, InvalidStyleError, UnknownMenuEntryError) as e: print(str(e), file=sys.stderr) diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index e4917f5e..f78a8b18 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -1,10 +1,12 @@ import logging +import pathlib import urllib.error import urllib.request from typing import Union, Mapping, Iterable, Dict, Any, List from .general import SysCommand from .output import log +from .storage import storage def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes: """ @@ -144,16 +146,22 @@ def re_rank_mirrors( def list_mirrors(sort_order :List[str] = ["https", "http"]) -> Dict[str, Any]: - url = "https://archlinux32.org/mirrorlist/?protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on" regions = {} - try: - response = urllib.request.urlopen(url) - except urllib.error.URLError as err: - log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="orange") - return regions + if storage['arguments']['offline']: + with pathlib.Path('/etc/pacman.d/mirrorlist').open('rb') as fh: + mirrorlist = fh.read() + else: + url = "https://archlinux32.org/mirrorlist/?protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on" + + try: + response = urllib.request.urlopen(url) + except urllib.error.URLError as err: + log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="orange") + return regions + + mirrorlist = response.read() - mirrorlist = response.read() if sort_order: mirrorlist = sort_mirrorlist(mirrorlist, sort_order=sort_order) @@ -170,5 +178,10 @@ def list_mirrors(sort_order :List[str] = ["https", "http"]) -> Dict[str, Any]: url = line.lstrip('#Server = ') regions[region][url] = True + elif line.startswith('Server = '): + regions.setdefault(region, {}) + + url = line.lstrip('Server = ') + regions[region][url] = True return regions diff --git a/archinstall/lib/models/network_configuration.py b/archinstall/lib/models/network_configuration.py index 4f135da5..e026e97b 100644 --- a/archinstall/lib/models/network_configuration.py +++ b/archinstall/lib/models/network_configuration.py @@ -39,8 +39,22 @@ class NetworkConfiguration: else: return 'Unknown type' - # for json serialization when calling json.dumps(...) on this class - def json(self): + def as_json(self) -> Dict: + exclude_fields = ['type'] + data = {} + for k, v in self.__dict__.items(): + if k not in exclude_fields: + if isinstance(v, list) and len(v) == 0: + v = '' + elif v is None: + v = '' + + data[k] = v + + return data + + def json(self) -> Dict: + # for json serialization when calling json.dumps(...) on this class return self.__dict__ def is_iso(self) -> bool: @@ -111,19 +125,10 @@ class NetworkConfigurationHandler: else: # not recognized return None - def _parse_manual_config(self, config: Dict[str, Any]) -> Union[None, List[NetworkConfiguration]]: - manual_configs: List = config.get('config', []) - - if not manual_configs: - return None - - if not isinstance(manual_configs, list): - log(_('Manual configuration setting must be a list')) - exit(1) - + def _parse_manual_config(self, configs: List[Dict[str, Any]]) -> Optional[List[NetworkConfiguration]]: configurations = [] - for manual_config in manual_configs: + for manual_config in configs: iface = manual_config.get('iface', None) if iface is None: @@ -135,7 +140,7 @@ class NetworkConfigurationHandler: NetworkConfiguration(NicType.MANUAL, iface=iface) ) else: - ip = config.get('ip', '') + ip = manual_config.get('ip', '') if not ip: log(_('Manual nic configuration with no auto DHCP requires an IP address'), fg='red') exit(1) @@ -145,32 +150,34 @@ class NetworkConfigurationHandler: NicType.MANUAL, iface=iface, ip=ip, - gateway=config.get('gateway', ''), - dns=config.get('dns', []), + gateway=manual_config.get('gateway', ''), + dns=manual_config.get('dns', []), dhcp=False ) ) return configurations - def parse_arguments(self, config: Any): - nic_type = config.get('type', None) - - if not nic_type: - # old style definitions - network_config = self._backwards_compability_config(config) - if network_config: - return network_config - return None - + def _parse_nic_type(self, nic_type: str) -> NicType: try: - type_ = NicType(nic_type) + return NicType(nic_type) except ValueError: options = [e.value for e in NicType] log(_('Unknown nic type: {}. Possible values are {}').format(nic_type, options), fg='red') exit(1) - if type_ != NicType.MANUAL: - self._configuration = NetworkConfiguration(type_) - else: # manual configuration settings + def parse_arguments(self, config: Any): + if isinstance(config, list): # new data format self._configuration = self._parse_manual_config(config) + elif nic_type := config.get('type', None): # new data format + type_ = self._parse_nic_type(nic_type) + + if type_ != NicType.MANUAL: + self._configuration = NetworkConfiguration(type_) + else: # manual configuration settings + self._configuration = self._parse_manual_config([config]) + else: # old style definitions + network_config = self._backwards_compability_config(config) + if network_config: + return network_config + return None diff --git a/archinstall/lib/models/password_strength.py b/archinstall/lib/models/password_strength.py new file mode 100644 index 00000000..61986bf0 --- /dev/null +++ b/archinstall/lib/models/password_strength.py @@ -0,0 +1,85 @@ +from enum import Enum + + +class PasswordStrength(Enum): + VERY_WEAK = 'very weak' + WEAK = 'weak' + MODERATE = 'moderate' + STRONG = 'strong' + + @property + def value(self): + match self: + case PasswordStrength.VERY_WEAK: return str(_('very weak')) + case PasswordStrength.WEAK: return str(_('weak')) + case PasswordStrength.MODERATE: return str(_('moderate')) + case PasswordStrength.STRONG: return str(_('strong')) + + def color(self): + match self: + case PasswordStrength.VERY_WEAK: return 'red' + case PasswordStrength.WEAK: return 'red' + case PasswordStrength.MODERATE: return 'yellow' + case PasswordStrength.STRONG: return 'green' + + @classmethod + def strength(cls, password: str) -> 'PasswordStrength': + digit = any(character.isdigit() for character in password) + upper = any(character.isupper() for character in password) + lower = any(character.islower() for character in password) + symbol = any(not character.isalnum() for character in password) + return cls._check_password_strength(digit, upper, lower, symbol, len(password)) + + @classmethod + def _check_password_strength( + cls, + digit: bool, + upper: bool, + lower: bool, + symbol: bool, + length: int + ) -> 'PasswordStrength': + # suggested evaluation + # https://github.com/archlinux/archinstall/issues/1304#issuecomment-1146768163 + if digit and upper and lower and symbol: + match length: + case num if 13 <= num: + return PasswordStrength.STRONG + case num if 11 <= num <= 12: + return PasswordStrength.MODERATE + case num if 7 <= num <= 10: + return PasswordStrength.WEAK + case num if num <= 6: + return PasswordStrength.VERY_WEAK + elif digit and upper and lower: + match length: + case num if 14 <= num: + return PasswordStrength.STRONG + case num if 11 <= num <= 13: + return PasswordStrength.MODERATE + case num if 7 <= num <= 10: + return PasswordStrength.WEAK + case num if num <= 6: + return PasswordStrength.VERY_WEAK + elif upper and lower: + match length: + case num if 15 <= num: + return PasswordStrength.STRONG + case num if 12 <= num <= 14: + return PasswordStrength.MODERATE + case num if 7 <= num <= 11: + return PasswordStrength.WEAK + case num if num <= 6: + return PasswordStrength.VERY_WEAK + elif lower or upper: + match length: + case num if 18 <= num: + return PasswordStrength.STRONG + case num if 14 <= num <= 17: + return PasswordStrength.MODERATE + case num if 9 <= num <= 13: + return PasswordStrength.WEAK + case num if num <= 8: + return PasswordStrength.VERY_WEAK + + return PasswordStrength.VERY_WEAK diff --git a/archinstall/lib/models/subvolume.py b/archinstall/lib/models/subvolume.py new file mode 100644 index 00000000..34a09227 --- /dev/null +++ b/archinstall/lib/models/subvolume.py @@ -0,0 +1,68 @@ +from dataclasses import dataclass +from typing import List, Any, Dict + + +@dataclass +class Subvolume: + name: str + mountpoint: str + compress: bool = False + nodatacow: bool = False + + def display(self) -> str: + options_str = ','.join(self.options) + return f'{_("Subvolume")}: {self.name:15} {_("Mountpoint")}: {self.mountpoint:20} {_("Options")}: {options_str}' + + @property + def options(self) -> List[str]: + options = [ + 'compress' if self.compress else '', + 'nodatacow' if self.nodatacow else '' + ] + return [o for o in options if len(o)] + + def json(self) -> Dict[str, Any]: + return { + 'name': self.name, + 'mountpoint': self.mountpoint, + 'compress': self.compress, + 'nodatacow': self.nodatacow + } + + @classmethod + def _parse(cls, config_subvolumes: List[Dict[str, Any]]) -> List['Subvolume']: + subvolumes = [] + for entry in config_subvolumes: + if not entry.get('name', None) or not entry.get('mountpoint', None): + continue + + subvolumes.append( + Subvolume( + entry['name'], + entry['mountpoint'], + entry.get('compress', False), + entry.get('nodatacow', False) + ) + ) + + return subvolumes + + @classmethod + def _parse_backwards_compatible(cls, config_subvolumes) -> List['Subvolume']: + subvolumes = [] + for name, mountpoint in config_subvolumes.items(): + if not name or not mountpoint: + continue + + subvolumes.append(Subvolume(name, mountpoint)) + + return subvolumes + + @classmethod + def parse_arguments(cls, config_subvolumes: Any) -> List['Subvolume']: + if isinstance(config_subvolumes, list): + return cls._parse(config_subvolumes) + elif isinstance(config_subvolumes, dict): + return cls._parse_backwards_compatible(config_subvolumes) + + raise ValueError('Unknown disk layout btrfs subvolume format') diff --git a/archinstall/lib/models/users.py b/archinstall/lib/models/users.py index 6052b73a..a8feb9ef 100644 --- a/archinstall/lib/models/users.py +++ b/archinstall/lib/models/users.py @@ -1,6 +1,8 @@ from dataclasses import dataclass from typing import Dict, List, Union, Any, TYPE_CHECKING +from .password_strength import PasswordStrength + if TYPE_CHECKING: _: Any @@ -25,8 +27,11 @@ class User: } def display(self) -> str: - password = '*' * len(self.password) - return f'{_("Username")}: {self.username:16} {_("Password")}: {password:16} sudo: {str(self.sudo)}' + password = '*' * (len(self.password) if self.password else 0) + if password: + strength = PasswordStrength.strength(self.password) + password += f' ({strength.value})' + return f'{_("Username")}: {self.username:16} {_("Password")}: {password:20} sudo: {str(self.sudo)}' @classmethod def _parse(cls, config_users: List[Dict[str, Any]]) -> List['User']: @@ -64,13 +69,13 @@ class User: ) -> List['User']: users = [] - # backwards compability + # backwards compatibility if isinstance(config_users, dict): users += cls._parse_backwards_compatible(config_users, False) else: users += cls._parse(config_users) - # backwards compability + # backwards compatibility if isinstance(config_superusers, dict): users += cls._parse_backwards_compatible(config_superusers, True) diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index 3e883a7b..96e8f3a1 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -4,7 +4,7 @@ import socket import struct from typing import Union, Dict, Any, List -from .exceptions import HardwareIncompatibilityError +from .exceptions import HardwareIncompatibilityError, SysCallError from .general import SysCommand from .output import log from .pacman import run_pacman @@ -33,14 +33,17 @@ def list_interfaces(skip_loopback :bool = True) -> Dict[str, str]: def check_mirror_reachable() -> bool: log("Testing connectivity to the Arch Linux mirrors ...", level=logging.INFO) - if run_pacman("-Sy").exit_code == 0: - return True - - elif os.geteuid() != 0: - log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red") + try: + if run_pacman("-Sy").exit_code == 0: + return True + elif os.geteuid() != 0: + log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red") + except SysCallError as err: + log(err, level=logging.DEBUG) return False + def update_keyring() -> bool: log("Updating archlinux-keyring ...", level=logging.INFO) if run_pacman("-Sy --noconfirm archlinux-keyring").exit_code == 0: diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 29b73bc4..709a7382 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -2,43 +2,83 @@ import logging import os import sys from pathlib import Path -from typing import Dict, Union, List, Any +from typing import Dict, Union, List, Any, Callable from .storage import storage +from dataclasses import asdict, is_dataclass class FormattedOutput: @classmethod - def values(cls, o: Any) -> Dict[str, Any]: - if hasattr(o, 'json'): + def values(cls, o: Any, class_formatter: str = None, filter_list: List[str] = None) -> Dict[str, Any]: + """ the original values returned a dataclass as dict thru the call to some specific methods + this version allows thru the parameter class_formatter to call a dynamicly selected formatting method. + Can transmit a filter list to the class_formatter, + """ + if class_formatter: + # if invoked per reference it has to be a standard function or a classmethod. + # A method of an instance does not make sense + if callable(class_formatter): + return class_formatter(o, filter_list) + # if is invoked by name we restrict it to a method of the class. No need to mess more + elif hasattr(o, class_formatter) and callable(getattr(o, class_formatter)): + func = getattr(o, class_formatter) + return func(filter_list) + # kept as to make it backward compatible + elif hasattr(o, 'as_json'): + return o.as_json() + elif hasattr(o, 'json'): return o.json() + elif is_dataclass(o): + return asdict(o) else: return o.__dict__ @classmethod - def as_table(cls, obj: List[Any]) -> str: + def as_table(cls, obj: List[Any], class_formatter: Union[str, Callable] = None, filter_list: List[str] = None) -> str: + """ variant of as_table (subtly different code) which has two additional parameters + filter which is a list of fields which will be shon + class_formatter a special method to format the outgoing data + + A general comment, the format selected for the output (a string where every data record is separated by newline) + is for compatibility with a print statement + As_table_filter can be a drop in replacement for as_table + """ + raw_data = [cls.values(o, class_formatter, filter_list) for o in obj] + # determine the maximum column size column_width: Dict[str, int] = {} - for o in obj: - for k, v in cls.values(o).items(): - column_width.setdefault(k, 0) - column_width[k] = max([column_width[k], len(str(v)), len(k)]) - + for o in raw_data: + for k, v in o.items(): + if not filter_list or k in filter_list: + column_width.setdefault(k, 0) + column_width[k] = max([column_width[k], len(str(v)), len(k)]) + + if not filter_list: + filter_list = (column_width.keys()) + # create the header lines output = '' - for key, width in column_width.items(): + key_list = [] + for key in filter_list: + width = column_width[key] key = key.replace('!', '') - output += key.ljust(width) + ' | ' - - output = output[:-3] + '\n' + key_list.append(key.ljust(width)) + output += ' | '.join(key_list) + '\n' output += '-' * len(output) + '\n' - for o in obj: - for k, v in cls.values(o).items(): - if '!' in k: - v = '*' * len(str(v)) - output += str(v).ljust(column_width[k]) + ' | ' - output = output[:-3] - output += '\n' + # create the data lines + for record in raw_data: + obj_data = [] + for key in filter_list: + width = column_width.get(key, len(key)) + value = record.get(key, '') + if '!' in key: + value = '*' * width + if isinstance(value,(int, float)) or (isinstance(value, str) and value.isnumeric()): + obj_data.append(str(value).rjust(width)) + else: + obj_data.append(str(value).ljust(width)) + output += ' | '.join(obj_data) + '\n' return output diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 99e3811c..0ff63610 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -60,7 +60,7 @@ def import_via_path(path :str, namespace :Optional[str] = None) -> ModuleType: log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) try: - del(sys.modules[namespace]) + del(sys.modules[namespace]) # noqa: E275 except: pass @@ -73,6 +73,7 @@ def find_nth(haystack :List[str], needle :str, n :int) -> int: def load_plugin(path :str) -> ModuleType: parsed_url = urllib.parse.urlparse(path) + log(f"Loading plugin {parsed_url}.", fg="gray", level=logging.INFO) # The Profile was not a direct match on a remote URL if not parsed_url.scheme: @@ -96,6 +97,7 @@ def load_plugin(path :str) -> ModuleType: if hasattr(sys.modules[namespace], 'Plugin'): try: plugins[namespace] = sys.modules[namespace].Plugin() + log(f"Plugin {plugins[namespace]} has been loaded.", fg="gray", level=logging.INFO) except Exception as err: log(err, level=logging.ERROR) log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py index dd7ddc88..8c358161 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -17,13 +17,13 @@ storage: Dict[str, Any] = { # os.path.abspath(f'{os.path.dirname(__file__)}/../examples') ], 'UPSTREAM_URL': 'https://raw.githubusercontent.com/archlinux/archinstall/master/profiles', - 'PROFILE_DB': None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing. + 'PROFILE_DB': None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabbing. 'LOG_PATH': '/var/log/archinstall', 'LOG_FILE': 'install.log', 'MOUNT_POINT': '/mnt/archinstall', 'ENC_IDENTIFIER': 'ainst', 'DISK_TIMEOUTS' : 1, # seconds 'DISK_RETRY_ATTEMPTS' : 5, # RETRY_ATTEMPTS * DISK_TIMEOUTS is used in disk operations - 'CMD_LOCALE':{'LC_ALL':'C'}, # default locale for execution commands. Can be overriden with set_cmd_locale() + 'CMD_LOCALE':{'LC_ALL':'C'}, # default locale for execution commands. Can be overridden with set_cmd_locale() 'CMD_LOCALE_DEFAULT':{'LC_ALL':'C'}, # should be the same as the former. Not be used except in reset_cmd_locale() } diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py index 3d2f0385..f459f94b 100644 --- a/archinstall/lib/systemd.py +++ b/archinstall/lib/systemd.py @@ -88,7 +88,7 @@ class Boot: if len(args) >= 2 and args[1]: log(args[1], level=logging.ERROR, fg='red') - log(f"The error above occured in a temporary boot-up of the installation {self.instance}", level=logging.ERROR, fg="red") + log(f"The error above occurred in a temporary boot-up of the installation {self.instance}", level=logging.ERROR, fg="red") shutdown = None shutdown_exit_code = -1 diff --git a/archinstall/lib/translation.py b/archinstall/lib/translation.py deleted file mode 100644 index 1a0e94e4..00000000 --- a/archinstall/lib/translation.py +++ /dev/null @@ -1,112 +0,0 @@ -from __future__ import annotations - -import json -import os -import gettext - -from pathlib import Path -from typing import List, Dict, Any, TYPE_CHECKING, Tuple -from .exceptions import TranslationError - -if TYPE_CHECKING: - _: Any - - -class LanguageDefinitions: - def __init__(self): - self._mappings = self._get_language_mappings() - - def _get_language_mappings(self) -> List[Dict[str, str]]: - locales_dir = Translation.get_locales_dir() - languages = Path.joinpath(locales_dir, 'languages.json') - - with open(languages, 'r') as fp: - return json.load(fp) - - def get_language(self, abbr: str) -> str: - for entry in self._mappings: - if entry['abbr'] == abbr: - return entry['lang'] - - raise ValueError(f'No language with abbrevation "{abbr}" found') - - -class DeferredTranslation: - def __init__(self, message: str): - self.message = message - - def __len__(self) -> int: - return len(self.message) - - def __str__(self) -> str: - translate = _ - if translate is DeferredTranslation: - return self.message - return translate(self.message) - - def __lt__(self, other) -> bool: - return self.message < other - - def __gt__(self, other) -> bool: - return self.message > other - - def __add__(self, other) -> DeferredTranslation: - if isinstance(other, str): - other = DeferredTranslation(other) - - concat = self.message + other.message - return DeferredTranslation(concat) - - def format(self, *args) -> str: - return self.message.format(*args) - - @classmethod - def install(cls): - import builtins - builtins._ = cls - - -class Translation: - def __init__(self, locales_dir): - self._languages = {} - - for names in self._get_translation_lang(): - try: - self._languages[names[0]] = gettext.translation('base', localedir=locales_dir, languages=names) - except FileNotFoundError as error: - raise TranslationError(f"Could not locate language file for '{names}': {error}") - - def activate(self, name): - if language := self._languages.get(name, None): - language.install() - else: - raise ValueError(f'Language not supported: {name}') - - @classmethod - def load_nationalization(cls) -> Translation: - locales_dir = cls.get_locales_dir() - return Translation(locales_dir) - - @classmethod - def get_locales_dir(cls) -> Path: - cur_path = Path(__file__).parent.parent - locales_dir = Path.joinpath(cur_path, 'locales') - return locales_dir - - @classmethod - def _defined_languages(cls) -> List[str]: - locales_dir = cls.get_locales_dir() - filenames = os.listdir(locales_dir) - return list(filter(lambda x: len(x) == 2, filenames)) - - @classmethod - def _get_translation_lang(cls) -> List[Tuple[str, str]]: - def_languages = cls._defined_languages() - languages = LanguageDefinitions() - return [(languages.get_language(lang), lang) for lang in def_languages] - - @classmethod - def get_available_lang(cls) -> List[str]: - def_languages = cls._defined_languages() - languages = LanguageDefinitions() - return [languages.get_language(lang) for lang in def_languages] diff --git a/archinstall/lib/translationhandler.py b/archinstall/lib/translationhandler.py new file mode 100644 index 00000000..ef33b8ec --- /dev/null +++ b/archinstall/lib/translationhandler.py @@ -0,0 +1,230 @@ +from __future__ import annotations + +import json +import logging +import os +import gettext +from dataclasses import dataclass + +from pathlib import Path +from typing import List, Dict, Any, TYPE_CHECKING, Optional +from .exceptions import TranslationError + +if TYPE_CHECKING: + _: Any + + +@dataclass +class Language: + abbr: str + name_en: str + 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 + + return f'{name} ({self.translation_percent}%)' + + def is_match(self, lang_or_translated_lang: str) -> bool: + if self.name_en == lang_or_translated_lang: + return True + elif self.translated_lang == lang_or_translated_lang: + return True + return False + + def json(self) -> str: + return self.name_en + + +class TranslationHandler: + def __init__(self): + 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 + + def _get_translations(self) -> List[Language]: + """ + Load all translated languages and return a list of such + """ + mappings = self._load_language_mappings() + defined_languages = self._provided_translations() + + languages = [] + + for short_form in defined_languages: + mapping_entry: Dict[str, Any] = next(filter(lambda x: x['abbr'] == short_form, mappings)) + 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 + translation = gettext.translation('base', localedir=self._get_locales_dir(), languages=(abbr, lang)) + + # calculate the percentage of total translated text to total number of messages + if abbr == 'en': + percent = 100 + else: + num_translations = self._get_catalog_size(translation) + percent = int((num_translations / self._total_messages) * 100) + # 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) + languages.append(language) + except FileNotFoundError as error: + raise TranslationError(f"Could not locate language file for '{lang}': {error}") + + return languages + + def _set_font(self, font: str): + """ + Set the provided font as the new terminal font + """ + from archinstall import SysCommand, log + try: + log(f'Setting font: {font}', level=logging.DEBUG) + SysCommand(f'setfont {font}') + except Exception: + log(f'Unable to set font {font}', level=logging.ERROR) + + def _load_language_mappings(self) -> List[Dict[str, Any]]: + """ + Load the mapping table of all known languages + """ + locales_dir = self._get_locales_dir() + languages = Path.joinpath(locales_dir, self._languages) + + with open(languages, 'r') as fp: + return json.load(fp) + + def _get_catalog_size(self, translation: gettext.NullTranslations) -> int: + """ + Get the number of translated messages for a translations + """ + # this is a very naughty way of retrieving the data but + # there's no alternative method exposed unfortunately + catalog = translation._catalog # type: ignore + messages = {k: v for k, v in catalog.items() if k and v} + return len(messages) + + def _get_total_active_messages(self) -> int: + """ + Get total messages that could be translated + """ + locales = self._get_locales_dir() + with open(f'{locales}/{self._base_pot}', 'r') as fp: + lines = fp.readlines() + msgid_lines = [line for line in lines if 'msgid' in line] + + return len(msgid_lines) - 1 # don't count the first line which contains the metadata + + def get_language_by_name(self, name: str) -> Language: + """ + Get a language object by it's name, e.g. English + """ + try: + return next(filter(lambda x: x.name_en == name, self._translated_languages)) + except Exception: + raise ValueError(f'No language with name found: {name}') + + def get_language_by_abbr(self, abbr: str) -> Language: + """ + Get a language object by its abbrevation, e.g. en + """ + try: + return next(filter(lambda x: x.abbr == abbr, self._translated_languages)) + except Exception: + raise ValueError(f'No language with abbreviation "{abbr}" found') + + def activate(self, language: Language): + """ + Set the provided language as the current translation + """ + language.translation.install() + + def _get_locales_dir(self) -> Path: + """ + Get the locales directory path + """ + cur_path = Path(__file__).parent.parent + locales_dir = Path.joinpath(cur_path, 'locales') + return locales_dir + + def _provided_translations(self) -> List[str]: + """ + Get a list of all known languages + """ + locales_dir = self._get_locales_dir() + filenames = os.listdir(locales_dir) + + translation_files = [] + for filename in filenames: + if len(filename) == 2 or filename == 'pt_BR': + translation_files.append(filename) + + return translation_files + + +class DeferredTranslation: + def __init__(self, message: str): + self.message = message + + def __len__(self) -> int: + return len(self.message) + + def __str__(self) -> str: + translate = _ + if translate is DeferredTranslation: + return self.message + return translate(self.message) + + def __lt__(self, other) -> bool: + return self.message < other + + def __gt__(self, other) -> bool: + return self.message > other + + def __add__(self, other) -> DeferredTranslation: + if isinstance(other, str): + other = DeferredTranslation(other) + + concat = self.message + other.message + return DeferredTranslation(concat) + + def format(self, *args) -> str: + return self.message.format(*args) + + @classmethod + def install(cls): + import builtins + builtins._ = cls diff --git a/archinstall/lib/user_interaction/__init__.py b/archinstall/lib/user_interaction/__init__.py index 8aba4b4d..a1ca2652 100644 --- a/archinstall/lib/user_interaction/__init__.py +++ b/archinstall/lib/user_interaction/__init__.py @@ -7,6 +7,6 @@ from .network_conf import ask_to_configure_network from .partitioning_conf import select_partition, select_encrypted_partitions 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) + select_additional_repositories, ask_hostname, add_number_of_parrallel_downloads) from .disk_conf import ask_for_main_filesystem_format, select_individual_blockdevice_usage, select_disk_layout, select_disk from .utils import get_password, do_countdown diff --git a/archinstall/lib/user_interaction/backwards_compatible_conf.py b/archinstall/lib/user_interaction/backwards_compatible_conf.py index d91690eb..296572d2 100644 --- a/archinstall/lib/user_interaction/backwards_compatible_conf.py +++ b/archinstall/lib/user_interaction/backwards_compatible_conf.py @@ -40,7 +40,7 @@ def generic_select( # We check that the options are iterable. If not we abort. Else we copy them to lists # it options is a dictionary we use the values as entries of the list # if options is a string object, each character becomes an entry - # if options is a list, we implictily build a copy to mantain immutability + # if options is a list, we implictily build a copy to maintain immutability if not isinstance(p_options, Iterable): log(f"Objects of type {type(p_options)} is not iterable, and are not supported at generic_select", fg="red") log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>", level=logging.WARNING) diff --git a/archinstall/lib/user_interaction/disk_conf.py b/archinstall/lib/user_interaction/disk_conf.py index 371d052f..b5ed6967 100644 --- a/archinstall/lib/user_interaction/disk_conf.py +++ b/archinstall/lib/user_interaction/disk_conf.py @@ -45,8 +45,8 @@ 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, - explode_on_interrupt=True, - explode_warning=warning + raise_error_on_interrupt=True, + raise_error_warning_msg=warning ).run() match choice.type_: diff --git a/archinstall/lib/user_interaction/general_conf.py b/archinstall/lib/user_interaction/general_conf.py index d4dc60db..6365014d 100644 --- a/archinstall/lib/user_interaction/general_conf.py +++ b/archinstall/lib/user_interaction/general_conf.py @@ -1,10 +1,9 @@ from __future__ import annotations import logging +import pathlib from typing import List, Any, Optional, Dict, TYPE_CHECKING -import archinstall - from ..menu.menu import MenuSelectionType from ..menu.text_input import TextInput @@ -14,9 +13,11 @@ from ..output import log from ..profiles import Profile, list_profiles from ..mirrors import list_mirrors -from ..translation import Translation +from ..translationhandler import Language, TranslationHandler from ..packages.packages import validate_package_list +from ..storage import storage + if TYPE_CHECKING: _: Any @@ -109,7 +110,7 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: list(mirrors.keys()), preset_values=preselected, multi=True, - explode_on_interrupt=True + raise_error_on_interrupt=True ).run() match selected_mirror.type_: @@ -118,10 +119,40 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: case _: return {selected: mirrors[selected] for selected in selected_mirror.value} -def select_archinstall_language(default='English'): - languages = Translation.get_available_lang() - language = Menu(_('Archinstall language'), languages, default_option=default).run() - return language +def select_archinstall_language(languages: List[Language], preset_value: Language) -> Language: + # these are the displayed language names which can either be + # the english name of a language or, if present, the + # 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 + + choice = Menu( + _('Archinstall language'), + 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: + 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) def select_profile(preset) -> Optional[Profile]: @@ -147,19 +178,19 @@ def select_profile(preset) -> Optional[Profile]: selection = Menu( title=title, p_options=list(options.keys()), - explode_on_interrupt=True, - explode_warning=warning + raise_error_on_interrupt=True, + raise_error_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: - archinstall.storage['profile_minimal'] = False - archinstall.storage['_selected_servers'] = [] - archinstall.storage['_desktop_profile'] = None - archinstall.arguments['desktop-environment'] = None - archinstall.arguments['gfx_driver_packages'] = None + 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: return None @@ -172,27 +203,61 @@ def ask_additional_packages_to_install(pre_set_packages: List[str] = []) -> List def read_packages(already_defined: list = []) -> list: display = ' '.join(already_defined) - input_packages = TextInput(_('Write additional packages to install (space separated, leave blank to skip): '), display).run() - return input_packages.split(' ') if input_packages else [] + input_packages = TextInput(_('Write additional packages to install (space separated, leave blank to skip): '), display).run().strip() + return input_packages.split() if input_packages else [] pre_set_packages = pre_set_packages if pre_set_packages else [] packages = read_packages(pre_set_packages) - while True: - if len(packages): - # Verify packages that were given - print(_("Verifying that additional packages exist (this might take a few seconds)")) - valid, invalid = validate_package_list(packages) + if not storage['arguments']['offline'] and not storage['arguments']['no_pkg_lookups']: + while True: + if len(packages): + # Verify packages that were given + print(_("Verifying that additional packages exist (this might take a few seconds)")) + valid, invalid = validate_package_list(packages) - if invalid: - log(f"Some packages could not be found in the repository: {invalid}", level=logging.WARNING, fg='red') - packages = read_packages(valid) - continue - break + if invalid: + log(f"Some packages could not be found in the repository: {invalid}", level=logging.WARNING, fg='red') + packages = read_packages(valid) + continue + break return packages +def add_number_of_parrallel_downloads(input_number :Optional[int] = None) -> Optional[int]: + max_downloads = 5 + print(_(f"This option enables the number of parallel downloads that can occur during installation")) + print(_(f"Enter the number of parallel downloads to be enabled.\n (Enter a value between 1 to {max_downloads})\nNote:")) + print(_(f" - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )")) + print(_(f" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )")) + print(_(f" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )")) + + while True: + try: + input_number = int(TextInput(_("[Default value: 0] > ")).run().strip() or 0) + if input_number <= 0: + input_number = 0 + elif input_number > max_downloads: + input_number = max_downloads + break + except: + print(_(f"Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]")) + + pacman_conf_path = pathlib.Path("/etc/pacman.conf") + with pacman_conf_path.open() as f: + pacman_conf = f.read().split("\n") + + with pacman_conf_path.open("w") as fwrite: + for line in pacman_conf: + if "ParallelDownloads" in line: + fwrite.write(f"ParallelDownloads = {input_number+1}\n") if not input_number == 0 else fwrite.write("#ParallelDownloads = 0\n") + else: + fwrite.write(f"{line}\n") + + return input_number + + def select_additional_repositories(preset: List[str]) -> List[str]: """ Allows the user to select additional repositories (multilib, and testing) if desired. @@ -209,7 +274,7 @@ def select_additional_repositories(preset: List[str]) -> List[str]: sort=False, multi=True, preset_values=preset, - explode_on_interrupt=True + raise_error_on_interrupt=True ).run() match choice.type_: diff --git a/archinstall/lib/user_interaction/manage_users_conf.py b/archinstall/lib/user_interaction/manage_users_conf.py index 567a2964..84ce3556 100644 --- a/archinstall/lib/user_interaction/manage_users_conf.py +++ b/archinstall/lib/user_interaction/manage_users_conf.py @@ -7,6 +7,7 @@ from .utils import get_password from ..menu import Menu from ..menu.list_manager import ListManager from ..models.users import User +from ..output import FormattedOutput if TYPE_CHECKING: _: Any @@ -18,56 +19,51 @@ class UserList(ListManager): """ def __init__(self, prompt: str, lusers: List[User]): - """ - param: prompt - type: str - param: lusers dict with the users already defined for the system - type: Dict - param: sudo. boolean to determine if we handle superusers or users. If None handles both types - """ self._actions = [ str(_('Add a user')), str(_('Change password')), str(_('Promote/Demote user')), str(_('Delete User')) ] - super().__init__(prompt, lusers, self._actions, self._actions[0]) + super().__init__(prompt, lusers, [self._actions[0]], self._actions[1:]) def reformat(self, data: List[User]) -> Dict[str, User]: - return {e.display(): e for e in data} + table = FormattedOutput.as_table(data) + rows = table.split('\n') - def action_list(self): - active_user = self.target if self.target else None + # these are the header rows of the table and do not map to any User 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 + display_data = {f' {rows[0]}': None, f' {rows[1]}': None} - if active_user is None: - return [self._actions[0]] - else: - return self._actions[1:] + for row, user in zip(rows[2:], data): + row = row.replace('|', '\\|') + display_data[row] = user - def exec_action(self, data: List[User]) -> List[User]: - if self.target: - active_user = self.target - else: - active_user = None + return display_data - if self.action == self._actions[0]: # add + def selected_action_display(self, user: User) -> str: + return user.username + + def handle_action(self, action: str, entry: Optional[User], data: List[User]) -> List[User]: + if action == self._actions[0]: # add new_user = self._add_user() if new_user is not None: # in case a user with the same username as an existing user # was created we'll replace the existing one data = [d for d in data if d.username != new_user.username] data += [new_user] - elif self.action == self._actions[1]: # change password - prompt = str(_('Password for user "{}": ').format(active_user.username)) + elif action == self._actions[1]: # change password + prompt = str(_('Password for user "{}": ').format(entry.username)) new_password = get_password(prompt=prompt) if new_password: - user = next(filter(lambda x: x == active_user, data), 1) + user = next(filter(lambda x: x == entry, data)) user.password = new_password - elif self.action == self._actions[2]: # promote/demote - user = next(filter(lambda x: x == active_user, data), 1) + elif action == self._actions[2]: # promote/demote + user = next(filter(lambda x: x == entry, data)) user.sudo = False if user.sudo else True - elif self.action == self._actions[3]: # delete - data = [d for d in data if d != active_user] + elif action == self._actions[3]: # delete + data = [d for d in data if d != entry] return data @@ -77,8 +73,7 @@ class UserList(ListManager): return False def _add_user(self) -> Optional[User]: - print(_('\nDefine a new user\n')) - prompt = str(_('Enter username (leave blank to skip): ')) + prompt = '\n\n' + str(_('Enter username (leave blank to skip): ')) while True: username = input(prompt).strip(' ') @@ -94,7 +89,9 @@ class UserList(ListManager): choice = Menu( str(_('Should "{}" be a superuser (sudo)?')).format(username), Menu.yes_no(), skip=False, - default_option=Menu.no() + default_option=Menu.no(), + clear_screen=False, + show_search_hint=False ).run() sudo = True if choice.value == Menu.yes() else False @@ -102,6 +99,5 @@ class UserList(ListManager): def ask_for_additional_users(prompt: str = '', defined_users: List[User] = []) -> List[User]: - prompt = prompt if prompt else _('Enter username (leave blank to skip): ') users = UserList(prompt, defined_users).run() return users diff --git a/archinstall/lib/user_interaction/network_conf.py b/archinstall/lib/user_interaction/network_conf.py index 5154d8b1..557e8ed8 100644 --- a/archinstall/lib/user_interaction/network_conf.py +++ b/archinstall/lib/user_interaction/network_conf.py @@ -2,7 +2,7 @@ from __future__ import annotations import ipaddress import logging -from typing import Any, Optional, TYPE_CHECKING, List, Union +from typing import Any, Optional, TYPE_CHECKING, List, Union, Dict from ..menu.menu import MenuSelectionType from ..menu.text_input import TextInput @@ -10,7 +10,7 @@ from ..models.network_configuration import NetworkConfiguration, NicType from ..networking import list_interfaces from ..menu import Menu -from ..output import log +from ..output import log, FormattedOutput from ..menu.list_manager import ListManager if TYPE_CHECKING: @@ -19,55 +19,55 @@ if TYPE_CHECKING: class ManualNetworkConfig(ListManager): """ - subclass of ListManager for the managing of network configuration accounts + subclass of ListManager for the managing of network configurations """ - def __init__(self, prompt: str, ifaces: Union[None, NetworkConfiguration, List[NetworkConfiguration]]): - """ - param: prompt - type: str - param: ifaces already defined previously - type: Dict - """ + def __init__(self, prompt: str, ifaces: List[NetworkConfiguration]): + self._actions = [ + str(_('Add interface')), + str(_('Edit interface')), + str(_('Delete interface')) + ] - if ifaces is not None and isinstance(ifaces, list): - display_values = {iface.iface: iface for iface in ifaces} - else: - display_values = {} + super().__init__(prompt, ifaces, [self._actions[0]], self._actions[1:]) + + def reformat(self, data: List[NetworkConfiguration]) -> Dict[str, Optional[NetworkConfiguration]]: + table = FormattedOutput.as_table(data) + rows = table.split('\n') - self._action_add = str(_('Add interface')) - self._action_edit = str(_('Edit interface')) - self._action_delete = str(_('Delete interface')) + # these are the header rows of the table and do not map to any User 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 + display_data: Dict[str, Optional[NetworkConfiguration]] = {f' {rows[0]}': None, f' {rows[1]}': None} - self._iface_actions = [self._action_edit, self._action_delete] + for row, iface in zip(rows[2:], data): + row = row.replace('|', '\\|') + display_data[row] = iface - super().__init__(prompt, display_values, self._iface_actions, self._action_add) + return display_data - def run_manual(self) -> List[NetworkConfiguration]: - ifaces = super().run() - if ifaces is not None: - return list(ifaces.values()) - return [] + def selected_action_display(self, iface: NetworkConfiguration) -> str: + return iface.iface if iface.iface else '' - def exec_action(self, data: Any): - if self.action == self._action_add: - iface_name = self._select_iface(data.keys()) + def handle_action(self, action: str, entry: Optional[NetworkConfiguration], data: List[NetworkConfiguration]): + if action == self._actions[0]: # add + iface_name = self._select_iface(data) if iface_name: iface = NetworkConfiguration(NicType.MANUAL, iface=iface_name) - data[iface_name] = self._edit_iface(iface) - elif self.target: - iface_name = list(self.target.keys())[0] - iface = data[iface_name] - - if self.action == self._action_edit: - data[iface_name] = self._edit_iface(iface) - elif self.action == self._action_delete: - del data[iface_name] + iface = self._edit_iface(iface) + data += [iface] + elif entry: + if action == self._actions[1]: # edit interface + data = [d for d in data if d.iface != entry.iface] + data.append(self._edit_iface(entry)) + elif action == self._actions[2]: # delete + data = [d for d in data if d != entry] return data - def _select_iface(self, existing_ifaces: List[str]) -> Optional[Any]: + def _select_iface(self, data: List[NetworkConfiguration]) -> Optional[Any]: all_ifaces = list_interfaces().values() + existing_ifaces = [d.iface for d in data] available = set(all_ifaces) - set(existing_ifaces) choice = Menu(str(_('Select interface to add')), list(available), skip=True).run() @@ -76,7 +76,7 @@ class ManualNetworkConfig(ListManager): return choice.value - def _edit_iface(self, edit_iface :NetworkConfiguration): + def _edit_iface(self, edit_iface: NetworkConfiguration): iface_name = edit_iface.iface modes = ['DHCP (auto detect)', 'IP (static)'] default_mode = 'DHCP (auto detect)' @@ -99,11 +99,13 @@ class ManualNetworkConfig(ListManager): gateway = None while 1: - gateway_input = TextInput(_('Enter your gateway (router) IP address or leave blank for none: '), - edit_iface.gateway).run().strip() + gateway = TextInput( + _('Enter your gateway (router) IP address or leave blank for none: '), + edit_iface.gateway + ).run().strip() try: - if len(gateway_input) > 0: - ipaddress.ip_address(gateway_input) + if len(gateway) > 0: + ipaddress.ip_address(gateway) break except ValueError: log("You need to enter a valid gateway (router) IP address.", level=logging.WARNING, fg='red') @@ -124,7 +126,9 @@ class ManualNetworkConfig(ListManager): return NetworkConfiguration(NicType.MANUAL, iface=iface_name) -def ask_to_configure_network(preset: Union[None, NetworkConfiguration, List[NetworkConfiguration]]) -> Optional[Union[List[NetworkConfiguration], NetworkConfiguration]]: +def ask_to_configure_network( + preset: Union[NetworkConfiguration, List[NetworkConfiguration]] +) -> Optional[NetworkConfiguration | List[NetworkConfiguration]]: """ Configure the network on the newly installed system """ @@ -150,8 +154,8 @@ def ask_to_configure_network(preset: Union[None, NetworkConfiguration, List[Netw list(network_options.values()), cursor_index=cursor_idx, sort=False, - explode_on_interrupt=True, - explode_warning=warning + raise_error_on_interrupt=True, + raise_error_warning_msg=warning ).run() match choice.type_: @@ -165,7 +169,7 @@ def ask_to_configure_network(preset: Union[None, NetworkConfiguration, List[Netw elif choice.value == network_options['network_manager']: return NetworkConfiguration(NicType.NM) elif choice.value == network_options['manual']: - manual = ManualNetworkConfig('Configure interfaces', preset) - return manual.run_manual() + preset_ifaces = preset if isinstance(preset, list) else [] + return ManualNetworkConfig('Configure interfaces', preset_ifaces).run() return preset diff --git a/archinstall/lib/user_interaction/partitioning_conf.py b/archinstall/lib/user_interaction/partitioning_conf.py index bfff5705..f2e6b881 100644 --- a/archinstall/lib/user_interaction/partitioning_conf.py +++ b/archinstall/lib/user_interaction/partitioning_conf.py @@ -5,7 +5,7 @@ from typing import List, Any, Dict, Union, TYPE_CHECKING, Callable, Optional from ..menu import Menu from ..menu.menu import MenuSelectionType -from ..output import log +from ..output import log, FormattedOutput from ..disk.validators import fs_types @@ -28,16 +28,31 @@ def current_partition_layout(partitions: List[Dict[str, Any]], with_idx: bool = pad_right = spaces - pad_left return f'{pad_right * " "}{name}{pad_left * " "}|' + def flatten_data(data: Dict[str, Any]) -> Dict[str, Any]: + flattened = {} + for k, v in data.items(): + if k == 'filesystem': + flat = flatten_data(v) + flattened.update(flat) + elif k == 'btrfs': + # we're going to create a separate table for the btrfs subvolumes + pass + else: + flattened[k] = v + return flattened + + display_data: List[Dict[str, Any]] = [flatten_data(entry) for entry in partitions] + column_names = {} # this will add an initial index to the table for each partition if with_idx: - column_names['index'] = max([len(str(len(partitions))), len('index')]) + column_names['index'] = max([len(str(len(display_data))), len('index')]) # determine all attribute names and the max length - # of the value among all partitions to know the width + # of the value among all display_data to know the width # of the table cells - for p in partitions: + for p in display_data: for attribute, value in p.items(): if attribute in column_names.keys(): column_names[attribute] = max([column_names[attribute], len(str(value)), len(attribute)]) @@ -50,7 +65,7 @@ def current_partition_layout(partitions: List[Dict[str, Any]], with_idx: bool = current_layout = f'{current_layout[:-1]}\n{"-" * len(current_layout)}\n' - for idx, p in enumerate(partitions): + for idx, p in enumerate(display_data): row = '' for name, max_len in column_names.items(): if name == 'index': @@ -62,6 +77,13 @@ def current_partition_layout(partitions: List[Dict[str, Any]], with_idx: bool = current_layout += f'{row[:-1]}\n' + # we'll create a separate table for the btrfs subvolumes + btrfs_subvolumes = [partition['btrfs']['subvolumes'] for partition in partitions if partition.get('btrfs', None)] + if len(btrfs_subvolumes) > 0: + for subvolumes in btrfs_subvolumes: + output = FormattedOutput.as_table(subvolumes) + current_layout += f'\n{output}' + if with_title: title = str(_('Current partition layout')) return f'\n\n{title}:\n\n{current_layout}' @@ -118,23 +140,10 @@ def get_default_partition_layout( return suggest_multi_disk_layout(block_devices, advanced_options=advanced_options) -def select_individual_blockdevice_usage(block_devices: list) -> Dict[str, Any]: - result = {} - - for device in block_devices: - layout = manage_new_and_existing_partitions(device) - result[device.path] = layout - - return result - - def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, Any]: # noqa: max-complexity: 50 block_device_struct = {"partitions": [partition.__dump__() for partition in block_device.partitions.values()]} original_layout = copy.deepcopy(block_device_struct) - # Test code: [part.__dump__() for part in block_device.partitions.values()] - # TODO: Squeeze in BTRFS subvolumes here - new_partition = str(_('Create a new partition')) suggest_partition_layout = str(_('Suggest partition layout')) delete_partition = str(_('Delete a partition')) @@ -187,6 +196,7 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, return original_layout elif task == save_and_exit: break + if task == new_partition: from ..disk import valid_parted_position @@ -200,8 +210,9 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, if fs_choice.type_ == MenuSelectionType.Esc: continue - prompt = _('Enter the start sector (percentage or block number, default: {}): ').format( - block_device.first_free_sector) + prompt = str(_('Enter the start sector (percentage or block number, default: {}): ')).format( + block_device.first_free_sector + ) start = input(prompt).strip() if not start.strip(): @@ -210,8 +221,9 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, else: end_suggested = '100%' - prompt = _('Enter the end sector of the partition (percentage or block number, ex: {}): ').format( - end_suggested) + prompt = str(_('Enter the end sector of the partition (percentage or block number, ex: {}): ')).format( + end_suggested + ) end = input(prompt).strip() if not end.strip(): @@ -224,7 +236,7 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, continue block_device_struct["partitions"].append({ - "type": "primary", # Strictly only allowed under MSDOS, but GPT accepts it so it's "safe" to inject + "type": "primary", # Strictly only allowed under MS-DOS, but GPT accepts it so it's "safe" to inject "start": start, "size": end, "mountpoint": None, @@ -351,18 +363,16 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, if partition is not None: if not block_device_struct["partitions"][partition].get('btrfs', {}): block_device_struct["partitions"][partition]['btrfs'] = {} - if not block_device_struct["partitions"][partition]['btrfs'].get('subvolumes', {}): - block_device_struct["partitions"][partition]['btrfs']['subvolumes'] = {} + if not block_device_struct["partitions"][partition]['btrfs'].get('subvolumes', []): + block_device_struct["partitions"][partition]['btrfs']['subvolumes'] = [] prev = block_device_struct["partitions"][partition]['btrfs']['subvolumes'] - result = SubvolumeList(_("Manage btrfs subvolumes for current partition"),prev).run() - if result: - block_device_struct["partitions"][partition]['btrfs']['subvolumes'] = result - else: - del block_device_struct["partitions"][partition]['btrfs'] + result = SubvolumeList(_("Manage btrfs subvolumes for current partition"), prev).run() + block_device_struct["partitions"][partition]['btrfs']['subvolumes'] = result return block_device_struct + def select_encrypted_partitions( title :str, partitions :List[Partition], @@ -374,11 +384,9 @@ def select_encrypted_partitions( if len(partition_indexes) == 0: return None - title = _('Select which partitions to mark for formatting:') - # show current partition layout: if len(partitions): - title += current_partition_layout(partitions) + '\n' + title += current_partition_layout(partitions, with_idx=True) + '\n' choice = Menu(title, partition_indexes, multi=multiple).run() diff --git a/archinstall/lib/user_interaction/subvolume_config.py b/archinstall/lib/user_interaction/subvolume_config.py index af783639..94150dee 100644 --- a/archinstall/lib/user_interaction/subvolume_config.py +++ b/archinstall/lib/user_interaction/subvolume_config.py @@ -1,146 +1,98 @@ -from typing import Dict, List +from typing import Dict, List, Optional, Any, TYPE_CHECKING from ..menu.list_manager import ListManager from ..menu.menu import MenuSelectionType -from ..menu.selection_menu import Selector, GeneralMenu from ..menu.text_input import TextInput from ..menu import Menu +from ..models.subvolume import Subvolume +from ... import FormattedOutput + +if TYPE_CHECKING: + _: Any -""" -UI classes -""" class SubvolumeList(ListManager): - def __init__(self,prompt,list): - self.ObjectNullAction = None # str(_('Add')) - self.ObjectDefaultAction = str(_('Add')) - super().__init__(prompt,list,None,self.ObjectNullAction,self.ObjectDefaultAction) - - def reformat(self, data: Dict) -> Dict: - def presentation(key :str, value :Dict): - text = _(" Subvolume :{:16}").format(key) - if isinstance(value,str): - text += _(" mounted at {:16}").format(value) - else: - if value.get('mountpoint'): - text += _(" mounted at {:16}").format(value['mountpoint']) - else: - text += (' ' * 28) - - if value.get('options',[]): - text += _(" with option {}").format(', '.join(value['options'])) - return text - - formatted = {presentation(k, v): k for k, v in data.items()} - return {k: v for k, v in sorted(formatted.items(), key=lambda e: e[0])} - - def action_list(self): - return super().action_list() - - def exec_action(self, data: Dict): - if self.target: - origkey, origval = list(self.target.items())[0] - else: - origkey = None - - if self.action == str(_('Delete')): - del data[origkey] - else: - if self.action == str(_('Add')): - self.target = {} - print(_('\n Fill the desired values for a new subvolume \n')) - with SubvolumeMenu(self.target,self.action) as add_menu: - for elem in ['name','mountpoint','options']: - add_menu.exec_option(elem) - else: - SubvolumeMenu(self.target,self.action).run() - - data.update(self.target) + def __init__(self, prompt: str, subvolumes: List[Subvolume]): + self._actions = [ + str(_('Add subvolume')), + str(_('Edit subvolume')), + str(_('Delete subvolume')) + ] + super().__init__(prompt, subvolumes, [self._actions[0]], self._actions[1:]) - return data + def reformat(self, data: List[Subvolume]) -> Dict[str, Optional[Subvolume]]: + table = FormattedOutput.as_table(data) + rows = table.split('\n') + + # these are the header rows of the table and do not map to any User 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 + display_data: Dict[str, Optional[Subvolume]] = {f' {rows[0]}': None, f' {rows[1]}': None} + + for row, subvol in zip(rows[2:], data): + row = row.replace('|', '\\|') + display_data[row] = subvol + + return display_data + def selected_action_display(self, subvolume: Subvolume) -> str: + return subvolume.name + + def _prompt_options(self, editing: Optional[Subvolume] = None) -> List[str]: + preset_options = [] + if editing: + preset_options = editing.options -class SubvolumeMenu(GeneralMenu): - def __init__(self,parameters,action=None): - self.data = parameters - self.action = action - self.ds = {} - self.ds['name'] = None - self.ds['mountpoint'] = None - self.ds['options'] = None - if self.data: - origkey,origval = list(self.data.items())[0] - self.ds['name'] = origkey - if isinstance(origval,str): - self.ds['mountpoint'] = origval - else: - self.ds['mountpoint'] = self.data[origkey].get('mountpoint') - self.ds['options'] = self.data[origkey].get('options') - - super().__init__(data_store=self.ds) - - def _setup_selection_menu_options(self): - # [str(_('Add')),str(_('Copy')),str(_('Edit')),str(_('Delete'))] - self._menu_options['name'] = Selector(str(_('Subvolume name ')), - self._select_subvolume_name if not self.action or self.action in (str(_('Add')),str(_('Copy'))) else None, - mandatory=True, - enabled=True) - self._menu_options['mountpoint'] = Selector(str(_('Subvolume mountpoint')), - self._select_subvolume_mount_point if not self.action or self.action in (str(_('Add')),str(_('Edit'))) else None, - enabled=True) - self._menu_options['options'] = Selector(str(_('Subvolume options')), - self._select_subvolume_options if not self.action or self.action in (str(_('Add')),str(_('Edit'))) else None, - enabled=True) - self._menu_options['save'] = Selector(str(_('Save')), - exec_func=lambda n,v:True, - enabled=True) - self._menu_options['cancel'] = Selector(str(_('Cancel')), - # func = lambda pre:True, - exec_func=lambda n,v:self.fast_exit(n), - enabled=True) - self.cancel_action = 'cancel' - self.save_action = 'save' - self.bottom_list = [self.save_action,self.cancel_action] - - def fast_exit(self,accion): - if self.option(accion).get_selection(): - for item in self.list_options(): - if self.option(item).is_mandatory(): - self.option(item).set_mandatory(False) - return True - - def exit_callback(self): - # we exit without moving data - if self.option(self.cancel_action).get_selection(): - return - if not self.ds['name']: - return - else: - key = self.ds['name'] - value = {} - if self.ds['mountpoint']: - value['mountpoint'] = self.ds['mountpoint'] - if self.ds['options']: - value['options'] = self.ds['options'] - self.data.update({key : value}) - - def _select_subvolume_name(self,value): - return TextInput(str(_("Subvolume name :")),value).run() - - def _select_subvolume_mount_point(self,value): - return TextInput(str(_("Select a mount point :")),value).run() - - def _select_subvolume_options(self,value) -> List[str]: - # def __init__(self, title, p_options, skip=True, multi=False, default_option=None, sort=True): choice = Menu( str(_("Select the desired subvolume options ")), ['nodatacow','compress'], skip=True, - preset_values=value, + preset_values=preset_options, multi=True ).run() if choice.type_ == MenuSelectionType.Selection: - return choice.value + return choice.value # type: ignore return [] + + def _add_subvolume(self, editing: Optional[Subvolume] = None) -> Optional[Subvolume]: + name = TextInput(f'\n\n{_("Subvolume name")}: ', editing.name if editing else '').run() + + if not name: + return None + + mountpoint = TextInput(f'\n{_("Subvolume mountpoint")}: ', editing.mountpoint if editing else '').run() + + if not mountpoint: + return None + + options = self._prompt_options(editing) + + subvolume = Subvolume(name, mountpoint) + subvolume.compress = 'compress' in options + subvolume.nodatacow = 'nodatacow' in options + + return subvolume + + def handle_action(self, action: str, entry: Optional[Subvolume], data: List[Subvolume]) -> List[Subvolume]: + if action == self._actions[0]: # add + new_subvolume = self._add_subvolume() + + if new_subvolume is not None: + # in case a user with the same username as an existing user + # was created we'll replace the existing one + data = [d for d in data if d.name != new_subvolume.name] + data += [new_subvolume] + elif entry is not None: + if action == self._actions[1]: # edit subvolume + new_subvolume = self._add_subvolume(entry) + + if new_subvolume is not None: + # we'll remove the original subvolume and add the modified version + data = [d for d in data if d.name != entry.name and d.name != new_subvolume.name] + data += [new_subvolume] + elif action == self._actions[2]: # delete + data = [d for d in data if d != entry] + + return data diff --git a/archinstall/lib/user_interaction/system_conf.py b/archinstall/lib/user_interaction/system_conf.py index 78daa6a5..94bbac30 100644 --- a/archinstall/lib/user_interaction/system_conf.py +++ b/archinstall/lib/user_interaction/system_conf.py @@ -32,8 +32,8 @@ def select_kernel(preset: List[str] = None) -> List[str]: sort=True, multi=True, preset_values=preset, - explode_on_interrupt=True, - explode_warning=warning + raise_error_on_interrupt=True, + raise_error_warning_msg=warning ).run() match choice.type_: @@ -67,8 +67,8 @@ def select_harddrives(preset: List[str] = []) -> List[str]: list(options.keys()), preset_values=list(preset_disks.keys()), multi=True, - explode_on_interrupt=True, - explode_warning=warning + raise_error_on_interrupt=True, + raise_error_warning_msg=warning ).run() match selected_harddrive.type_: diff --git a/archinstall/lib/user_interaction/utils.py b/archinstall/lib/user_interaction/utils.py index fa079bc2..7ee6fc07 100644 --- a/archinstall/lib/user_interaction/utils.py +++ b/archinstall/lib/user_interaction/utils.py @@ -7,6 +7,7 @@ import time from typing import Any, Optional, TYPE_CHECKING from ..menu import Menu +from ..models.password_strength import PasswordStrength from ..output import log if TYPE_CHECKING: @@ -16,42 +17,23 @@ if TYPE_CHECKING: SIG_TRIGGER = None -def check_password_strong(passwd: str) -> bool: - symbol_count = 0 - if any(character.isdigit() for character in passwd): - symbol_count += 10 - if any(character.isupper() for character in passwd): - symbol_count += 26 - if any(character.islower() for character in passwd): - symbol_count += 26 - if any(not character.isalnum() for character in passwd): - symbol_count += 40 - - if symbol_count**len(passwd) < 10e20: - prompt = str(_("The password you are using seems to be weak, are you sure you want to use it?")) - choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run() - return choice.value == Menu.yes() - - return True - - def get_password(prompt: str = '') -> Optional[str]: if not prompt: prompt = _("Enter a password: ") - while passwd := getpass.getpass(prompt): - if len(passwd.strip()) <= 0: + while password := getpass.getpass(prompt): + if len(password.strip()) <= 0: break - if not check_password_strong(passwd): - continue + strength = PasswordStrength.strength(password) + log(f'Password strength: {strength.value}', fg=strength.color()) passwd_verification = getpass.getpass(prompt=_('And one more time for verification: ')) - if passwd != passwd_verification: + if password != passwd_verification: log(' * Passwords did not match * ', fg='red') continue - return passwd + return password return None diff --git a/archinstall/locales/README.md b/archinstall/locales/README.md index 70822c05..37dc32e3 100644 --- a/archinstall/locales/README.md +++ b/archinstall/locales/README.md @@ -1,11 +1,29 @@ # Nationalization -Archinstall supports multiple languages, which depend on translations coming from the community :) +Archinstall supports multiple languages, which depend on translations coming from the community :) -New languages can be added simply by creating a new folder with the proper language abbrevation (see list `languages.json` if unsure). +## 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. + +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). + +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}, +``` + +## Adding new languages + +New languages can be added simply by creating a new folder with the proper language abbreviation (see list `languages.json` if unsure). Run the following command to create a new template for a language ``` - mkdir -p <abbr>/LC_MESSAGES/ && touch <abbr>/LC_MESSAGES/base.po +mkdir -p <abbr>/LC_MESSAGES/ && touch <abbr>/LC_MESSAGES/base.po ``` After that run the script `./locales_generator.sh` it will automatically populate the new `base.po` file with the strings that @@ -31,3 +49,10 @@ 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": "Polskie"} +``` diff --git a/archinstall/locales/ar/LC_MESSAGES/base.mo b/archinstall/locales/ar/LC_MESSAGES/base.mo Binary files differnew file mode 100644 index 00000000..6218cc97 --- /dev/null +++ b/archinstall/locales/ar/LC_MESSAGES/base.mo diff --git a/archinstall/locales/ar/LC_MESSAGES/base.po b/archinstall/locales/ar/LC_MESSAGES/base.po new file mode 100644 index 00000000..51b6c3d6 --- /dev/null +++ b/archinstall/locales/ar/LC_MESSAGES/base.po @@ -0,0 +1,784 @@ +# Header entry was created by Lokalize. +# +# zer0-x, 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2022-06-16 03:35+0300\n" +"Last-Translator: zer0-x\n" +"Language-Team: Arabic\n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 22.04.2\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\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 "هل تريد استخدام swap أو 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 "إذا كنت ترغب في متصفح الويب ، مثل 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 "استخدم مُدير الشبكة (ضروري لإعداد الإنترنت باستخدام واجهة رسومية في جنوم و كيدي)" + +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 "" + +msgid "Enter your DNS servers (space separated, blank for none): " +msgstr "" + +msgid "Select which filesystem your main partition should use" +msgstr "" + +msgid "Current partition layout" +msgstr "" + +msgid "" +"Select what to do with\n" +"{}" +msgstr "" + +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 "" + +msgid "" +"{}\n" +"\n" +"Select by index which partition to mount where" +msgstr "" + +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr "" + +msgid "Select where to mount partition (leave blank to remove mountpoint): " +msgstr "" + +msgid "" +"{}\n" +"\n" +"Select which partition to mask for formatting" +msgstr "" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as encrypted" +msgstr "" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as bootable" +msgstr "" + +msgid "" +"{}\n" +"\n" +"Select which partition to set a filesystem on" +msgstr "" + +msgid "Enter a desired filesystem type for the partition: " +msgstr "" + +msgid "Archinstall language" +msgstr "" + +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 "" + +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "" + +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "" + +msgid "" +"\n" +"\n" +"Select a graphics driver or leave blank to install all open-source drivers" +msgstr "" + +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 "" + +msgid "Error: Listing profiles on URL \"{}\" resulted in:" +msgstr "" + +msgid "Error: Could not decode \"{}\" result as JSON:" +msgstr "" + +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 "" + +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 "" + +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 "" + +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 "" + +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 "" + +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 "" + +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 "" + +msgid "Enter a username to create an additional user (leave blank to skip): " +msgstr "" + +msgid "Use ESC to skip\n" +msgstr "" + +msgid "" +"\n" +" Choose an object from the list, and select one of the available actions for it to execute" +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Confirm and exit" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Copy" +msgstr "" + +msgid "Edit" +msgstr "" + +msgid "Delete" +msgstr "" + +#, fuzzy +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 "" + +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "" + +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "" + +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 "" + +msgid "User Name : " +msgstr "" + +msgid "Should {} be a superuser (sudoer)?" +msgstr "" + +msgid "Define users with sudo privilege: " +msgstr "" + +msgid "No network configuration" +msgstr "" + +msgid "Set desired subvolumes on a btrfs partition" +msgstr "" + +msgid "" +"{}\n" +"\n" +"Select which partition to set subvolumes on" +msgstr "" + +msgid "Manage btrfs subvolumes for current partition" +msgstr "" + +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 "" + +msgid "Either root-password or at least 1 superuser must be specified" +msgstr "" + +msgid "Manage superuser accounts: " +msgstr "" + +msgid "Manage ordinary user accounts: " +msgstr "" + +msgid " Subvolume :{:16}" +msgstr "" + +msgid " mounted at {:16}" +msgstr "" + +msgid " with option {}" +msgstr "" + +msgid "" +"\n" +" Fill the desired values for a new subvolume \n" +msgstr "" + +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 "" + +msgid "[!] A log file has been created here: {}" +msgstr "" + +msgid "Would you like to use BTRFS subvolumes with a default structure?" +msgstr "" + +msgid "Would you like to use BTRFS compression?" +msgstr "" + +msgid "Would you like to create a separate partition for /home?" +msgstr "" + +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "" + +msgid "Minimum capacity for /home partition: {}GB\n" +msgstr "" + +msgid "Minimum capacity for Arch Linux partition: {}GB" +msgstr "" + +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 "" + +msgid "Manual nic configuration with no auto DHCP requires an IP address" +msgstr "" + +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 "" + +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 "" + +msgid "Select your desired desktop environment" +msgstr "" + +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "" + +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "" + +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 "" + +msgid "Press Enter to continue." +msgstr "" + +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "" + +msgid "Are you sure you want to reset this setting?" +msgstr "" + +msgid "Select one or more hard drives to use and configure\n" +msgstr "" + +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 "" + +msgid "No audio server" +msgstr "" + +msgid "(default)" +msgstr "" + +msgid "Use ESC to skip" +msgstr "" + +msgid "" +"Use CTRL+C to reset current selection\n" +"\n" +msgstr "" + +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 "" + +msgid "Select one of the disks or skip and use /mnt as default" +msgstr "" + +msgid "Select which partitions to mark for formatting:" +msgstr "" + +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +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 "" + +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 "" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +msgid "ESC to skip" +msgstr "" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 6db91789..0b08b337 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -414,7 +414,7 @@ msgstr "" msgid "Delete" msgstr "" -msgid "Select an action for < {} >" +msgid "Select an action for '{}'" msgstr "" msgid "Copy to new key:" @@ -652,7 +652,7 @@ msgid "" msgstr "" msgid "" -"Choose which servers to install, if none then a minimal installation wil be " +"Choose which servers to install, if none then a minimal installation will be " "done" msgstr "" @@ -760,3 +760,78 @@ msgstr "" msgid "Should \"{}\" be a superuser (sudo)?" msgstr "" + +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 "" + +msgid "" +" - Maximum value : {max_downloads} ( Allows {max_downloads} parallel " +"downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid "" +" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a " +"time )" +msgstr "" + +msgid "" +" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 " +"download at a time )" +msgstr "" + +#, python-brace-format +msgid "" +"Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to " +"disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +msgid "ESC to skip" +msgstr "" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + +msgid "[Default value: 0] > " +msgstr "" diff --git a/archinstall/locales/cs/LC_MESSAGES/base.mo b/archinstall/locales/cs/LC_MESSAGES/base.mo Binary files differindex f9aa3407..b175a54e 100644 --- a/archinstall/locales/cs/LC_MESSAGES/base.mo +++ b/archinstall/locales/cs/LC_MESSAGES/base.mo diff --git a/archinstall/locales/cs/LC_MESSAGES/base.po b/archinstall/locales/cs/LC_MESSAGES/base.po index 935f9ba2..733c9cae 100644 --- a/archinstall/locales/cs/LC_MESSAGES/base.po +++ b/archinstall/locales/cs/LC_MESSAGES/base.po @@ -3,13 +3,13 @@ msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" -"Last-Translator: tajnymag\n" +"Last-Translator: walken <walken@centrum.cz>\n" "Language-Team: \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.0.1\n" +"X-Generator: Poedit 3.1\n" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Soubor protokolu byl vytvořen zde: {} {}" @@ -51,13 +51,13 @@ msgid "Choose an audio server" msgstr "Zvolte audio server" msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." -msgstr "Bude nainstalovány pouze balíčky jako base, base-devel, linux, linux-firmware, efibootmgr a volitelné balíčky profilu." +msgstr "Budou nainstalovány pouze balíčky jako base, base-devel, linux, linux-firmware, efibootmgr a volitelné balíčky profilu." msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." -msgstr "Pokud si přejete nainstalovat webový prohlížeč, jako je například firefox nebo chromium, můžete jej zadat do následujícího pole." +msgstr "Pokud si přejete nainstalovat webový prohlížeč, jako je například Firefox nebo Chromium, můžete jej zadat do následujícího pole." msgid "Write additional packages to install (space separated, leave blank to skip): " -msgstr "Zadejte další balíčky k instalaci (odělené mezerou, ponechte prázdné k přeskočení): " +msgstr "Zadejte další balíčky k instalaci (oddělené mezerou, ponechte prázdné k přeskočení): " msgid "Copy ISO network configuration to installation" msgstr "Zkopírovat do instalace konfiguraci sítě z ISO" @@ -66,7 +66,7 @@ msgid "Use NetworkManager (necessary to configure internet graphically in GNOME msgstr "Použít NetworkManager (potřebné pro grafickou konfiguraci v GNOME a KDE)" msgid "Select one network interface to configure" -msgstr "Zvolte zařízení, které konfigurovat" +msgstr "Zvolte síťové rozhraní ke konfiguraci" msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" msgstr "Zvolte který režim má být nastaven pro \"{}\" nebo přeskočte pro použití výchozího režimu \"{}\"" @@ -185,7 +185,7 @@ msgid "Select keyboard layout" msgstr "Zvolte rozložení klávesnice" msgid "Select one of the regions to download packages from" -msgstr "Zvolte jeden z regionů ze kterého stahovat balíčky" +msgstr "Zvolte region ze kterého se budou stahovat balíčky" msgid "Select one or more hard drives to use and configure" msgstr "Zvolte jeden nebo více pevných disků k použití a konfiguraci" @@ -272,7 +272,7 @@ msgid "Superuser account" msgstr "Účet superuživatele" msgid "User account" -msgstr "Uživatelský úšet" +msgstr "Uživatelský účet" msgid "Profile" msgstr "Profil" @@ -374,7 +374,7 @@ msgid "Create a required super-user with sudo privileges: " msgstr "Vytvořte povinný účet superuživatele s oprávněními sudo: " msgid "Enter root password (leave blank to disable root): " -msgstr "Zadejte heslo uživatele root (ponechte prázdné k zakázání uživatele root)" +msgstr "Zadejte heslo uživatele root (ponechte prázdné k zakázání uživatele root): " msgid "Password for user \"{}\": " msgstr "Heslo pro uživatele \"{}\": " @@ -390,7 +390,7 @@ msgid "" "For more information, please check the Arch wiki" msgstr "" "Pro fungování NTP může být vyžadován hardwarový čas a další kroky po konfiguraci.\n" -"Pro další informace navštivte Arch Wiki." +"Pro další informace navštivte Arch Wiki" msgid "Enter a username to create an additional user (leave blank to skip): " msgstr "Zadejte uživatelské jméno k přidání dalšího uživatele (ponechte prázdné k přeskočení): " @@ -423,8 +423,8 @@ msgstr "Upravit" msgid "Delete" msgstr "Smazat" -msgid "Select an action for < {} >" -msgstr "Zvolte akci pro < {} >" +msgid "Select an action for '{}'" +msgstr "Zvolte akci pro '{}'" msgid "Copy to new key:" msgstr "Zkopírovat k novému klíči:" @@ -540,13 +540,13 @@ msgid "Manage ordinary user accounts: " msgstr "Spravovat běžné účty: " msgid " Subvolume :{:16}" -msgstr "Podsvazek :{:16}" +msgstr " Podsvazek :{:16}" msgid " mounted at {:16}" -msgstr "připojen na :{:16}" +msgstr " připojen na :{:16}" msgid " with option {}" -msgstr "s přepínačem {}" +msgstr " s přepínačem {}" msgid "" "\n" @@ -556,7 +556,7 @@ msgstr "" "Zadejte požadované hodnoty pro nový podsvazek \n" msgid "Subvolume name " -msgstr "Název podsvazku" +msgstr "Název podsvazku " msgid "Subvolume mountpoint" msgstr "Přípojný bod podsvazku" @@ -568,16 +568,16 @@ msgid "Save" msgstr "Uložit" msgid "Subvolume name :" -msgstr "Název podsvazku" +msgstr "Název podsvazku:" msgid "Select a mount point :" msgstr "Zvolte přípojný bod:" msgid "Select the desired subvolume options " -msgstr "Zvolte požadované přepínače podsvazku" +msgstr "Zvolte požadované přepínače podsvazku " msgid "Define users with sudo privilege, by username: " -msgstr "Specifikace uživatelů s oprávněními sudo, pomocí uživatelského jména:" +msgstr "Specifikace uživatelů s oprávněními sudo, pomocí uživatelského jména: " msgid "[!] A log file has been created here: {}" msgstr "[!] Soubor s protokoly byl uložen zde: {}" @@ -654,8 +654,8 @@ msgstr "Základní instalace, která vám umožní si nastavit Arch Linux jakkol msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Nabízí výběr různých serverových balíčků k instalaci a aktivaci, např. httpd, nginx, mariadb" -msgid "Choose which servers to install, if none then a minimal installation wil be done" -msgstr "Vyberte servery, které mají být nainstalovány, pokud nezvolíte žádné, bude provedena jen základní instalace" +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Vyberte, které servery mají být nainstalovány, pokud nezvolíte žádné, bude provedena jen základní instalace" msgid "Installs a minimal system as well as xorg and graphics drivers." msgstr "Nainstaluje minimalistický systém spolu s xorg a ovladači grafiky." @@ -703,13 +703,13 @@ msgid "" msgstr "Pomocí CTRL+C zrušíte stávající výběr\n" msgid "Copy to: " -msgstr "Zkopírovat do:" +msgstr "Zkopírovat do: " msgid "Edit: " -msgstr "Upravit:" +msgstr "Upravit: " msgid "Key: " -msgstr "Klíč:" +msgstr "Klíč: " msgid "Edit {}: " msgstr "Upravit {}: " @@ -743,3 +743,81 @@ msgstr "Volné místo" msgid "Bus-type" msgstr "Typ sběrnice" + +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Musí být zadáno heslo správce (root) nebo musí být specifikován alespoň jeden uživatel s sudo oprávněními" + +msgid "Enter username (leave blank to skip): " +msgstr "Zadejte uživatelské jméno (ponechte prázdné k přeskočení): " + +msgid "The username you entered is invalid. Try again" +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 "very weak" +msgstr "velmi slabé" + +msgid "weak" +msgstr "slabé" + +msgid "moderate" +msgstr "středně silné" + +msgid "strong" +msgstr "silné" + +msgid "Add subvolume" +msgstr "Přidat podsvazek" + +msgid "Edit subvolume" +msgstr "Upravit podsvazek" + +msgid "Delete subvolume" +msgstr "Smazat podsvazek" + +msgid "Configured {} interfaces" +msgstr "Nakonfigurováno {} rozhraní" + +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "Tato možnost povolí specifikovaný počet paralelních stahování, která mohou nastat při instalaci" + +#, 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 "" +"Zadejte povolený počet paralelních stahování.\n" +" (Zadejte hodnotu mezi 1 a {max_downloads})\n" +"Poznámka:" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - Maximální hodnota : {max_downloads} (Povolí {max_downloads} paralelních stahování, povolí {max_downloads+1} stahování naráz )" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - Minimální hodnota : 1 (Povolí 1 paralelní stahování, povolí 2 stahování naráz)" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr " - Zakázáno/Výchozí : 0 (Zakáže paralelní stahování, povolí pouze 1 stahování naráz)" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "Neplatný vstup! Zkuste to, prosím, znovu s platným vstupem [1 až {max_downloads}, nebo 0 pro vypnutí]" + +msgid "Parallel Downloads" +msgstr "Paralelní stahování" + +#, fuzzy +msgid "ESC to skip" +msgstr "Pomocí ESC přeskočíte" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/de/LC_MESSAGES/base.mo b/archinstall/locales/de/LC_MESSAGES/base.mo Binary files differindex 3d58d749..ca3f2971 100644 --- a/archinstall/locales/de/LC_MESSAGES/base.mo +++ b/archinstall/locales/de/LC_MESSAGES/base.mo diff --git a/archinstall/locales/de/LC_MESSAGES/base.po b/archinstall/locales/de/LC_MESSAGES/base.po index 51ecd8e9..46782bc3 100644 --- a/archinstall/locales/de/LC_MESSAGES/base.po +++ b/archinstall/locales/de/LC_MESSAGES/base.po @@ -255,10 +255,12 @@ msgstr "Lokale Kodierung" msgid "Drive(s)" msgstr "Laufwerke" -msgid "Select disk layout" -msgstr "Laufwerke-layout auswählen" +#, fuzzy +msgid "Disk layout" +msgstr "Laufwerke-layout speichern" -msgid "Set encryption password" +#, fuzzy +msgid "Encryption password" msgstr "Verschlüsselungspasswort angeben" msgid "Swap" @@ -267,7 +269,8 @@ msgstr "Swap" msgid "Bootloader" msgstr "Bootloader" -msgid "root password" +#, fuzzy +msgid "Root password" msgstr "Root Passwort" msgid "Superuser account" @@ -425,8 +428,8 @@ msgstr "Bearbeiten" msgid "Delete" msgstr "Löschen" -msgid "Select an action for < {} >" -msgstr "Wählen sie eine Aktion aus für < {} >" +msgid "Select an action for '{}'" +msgstr "Wählen sie eine Aktion aus für '{}'" msgid "Copy to new key:" msgstr "Kopieren nach neuem Schlüssel:" @@ -659,7 +662,8 @@ msgstr "Eine sehr minimale Installation welche es erlaubt Arch Linux weitgehend msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Auswahl von Serverpaketen welche installiert werden sollen, z.B. httpd, nginx, mariadb" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +#, fuzzy +msgid "Choose which servers to install, if none then a minimal installation will be done" msgstr "Wählen sie die gewünschten Server aus welche installiert werden sollen" msgid "Installs a minimal system as well as xorg and graphics drivers." @@ -741,6 +745,108 @@ msgstr "" "\n" "Bitte wählen sie welche Partition formatiert werden soll" +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Free space" +msgstr "" + +msgid "Bus-type" +msgstr "" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Entweder root Passwort oder wenigstens 1 super-user muss konfiguriert sein" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Geben sie einen weiteren Benutzernamen an der angelegt werden soll (leer lassen um zu Überspringen): " + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Subvolume :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Benutzerkonto löschen" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "ESC drücken um zu überspringen" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + +#~ msgid "Select disk layout" +#~ msgstr "Laufwerke-layout auswählen" + #~ msgid "Add :" #~ msgstr "Hinzufügen :" diff --git a/archinstall/locales/el/LC_MESSAGES/base.mo b/archinstall/locales/el/LC_MESSAGES/base.mo Binary files differnew file mode 100644 index 00000000..beae2659 --- /dev/null +++ b/archinstall/locales/el/LC_MESSAGES/base.mo diff --git a/archinstall/locales/el/LC_MESSAGES/base.po b/archinstall/locales/el/LC_MESSAGES/base.po new file mode 100644 index 00000000..6425ba96 --- /dev/null +++ b/archinstall/locales/el/LC_MESSAGES/base.po @@ -0,0 +1,830 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.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 " Παρακαλώ επισυνάψτε αυτό το issue (και αρχείο) στο 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 "Θα θέλατε να χρησιμοποιήσετε swap με 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 "Θα έπρεπε αυτός ο χρήστης να είναι ένας υπερχρήστης (χρήστης sudo);" + +msgid "Select a timezone" +msgstr "Επιλέξτε μία ζώνη ώρας" + +msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" +msgstr "Θα θέλατε να χρησιμοποιήσετε το GRUB ως bootloader αντί του systemd-boot;" + +msgid "Choose a bootloader" +msgstr "Επιλέξτε έναν bootloader" + +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 "Εάν επιθυμείτε έναν περιηγητή διαδικτύου, όπως ο firefox ή ο chromium, πρέπει να το καθορίσετε στο επακόλουθο prompt." + +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 "Επιλέξτε ποιο mode να διαμορφωθεί για το \"{}\" ή παραλείψτε για να χρησιμοποιηθεί το default mode \"{}\"" + +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 του router σας ή αφήστε άδειο για καμία διεύθυνση: " + +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 "Εισάγετε τον start sector (ποσοστό ή αριθμό block, προκαθορισμένο {}): " + +msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " +msgstr "Εισάγετε τον end sector της διαμέρισης (ποσοστό ή αριθμό block, πχ: {}) " + +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" +"Επιλέξτε ποια διαμέριση να γίνει mount που, μέσω δείκτη" + +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Τα σημεία mount της διαμέρισης είναι σχετικά ως προς το εσωτερικό της εγκατάστασης, για παράδειγμα το boot θα ήταν /boot." + +msgid "Select where to mount partition (leave blank to remove mountpoint): " +msgstr "Επιλέξτε που να γίνει mount η διαμέρισιη (αφήστε άδειο για να διαγραφεί το σημείο mount): " + +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" +"Επιλέξτε ποια διαμέριση να σημειωθεί ως bootable" + +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 "Επιλέξτε τι θέλετε να κάνετε με τις επιλεγμένες συσκευές block" + +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 "Επιλέξτε ποια kernels να χρησιμοποιηθούν ή αφήστε άδειο για το προκαθορισμένο \"{}\"" + +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 ώστε να συνεχίσετε. Δείτε `man parted` για έγκυρους fs-type." + +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 "Περιοχή mirror" + +msgid "Locale language" +msgstr "Τοπική γλώσσα" + +msgid "Locale encoding" +msgstr "Τοπική κωδικοποίηση" + +msgid "Drive(s)" +msgstr "Δίσκος(οι)" + +msgid "Disk layout" +msgstr "Διάταξη δίσκου" + +msgid "Encryption password" +msgstr "Κωδικός κρυπτογράφησης" + +msgid "Swap" +msgstr "Swap" + +msgid "Bootloader" +msgstr "Bootloader" + +msgid "Root password" +msgstr "Κωδικός root" + +msgid "Superuser account" +msgstr "Λογαριασμός υπερχρήστη" + +msgid "User account" +msgstr "Λογαριασμός χρήστη" + +msgid "Profile" +msgstr "Προφίλ" + +msgid "Audio" +msgstr "Ήχος" + +msgid "Kernels" +msgstr "Kernels" + +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" +"και θα χρησιμοποιηθεί οποιαδήποτε εγκατάσταση δίσκου είναι mount στο {} (πειραματικό)\n" +"ΠΡΟΣΟΧΗ: Το archinstall δεν μπορεί να ελέγξει την καταλληλότητα αυτής της εγκατάστασης\n" +"Θέλετε να συνεχίσετε;" + +msgid "Re-using partition instance: {}" +msgstr "Επαναχρησιμοποιώντας την instance διαμέρισης: {}" + +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 "Εκχώρηση σημείου mount για μία διαμέριση" + +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 (αυτόματο για /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 "Άγνωστος τύπος 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 lock δεν εξήλθε. Παρακαλώ καθαρίστε τυχόν συνεδρίες pacman πριν τη χρήση του archinstall." + +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 "Θα έπρεπε ο {} να είναι υπερχρήστης (χρήστης sudo);" + +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 " Έχει γίνει mount στο {: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 "Σημείο mount υποόγκου" + +msgid "Subvolume options" +msgstr "Επιλογές υποόγκου" + +msgid "Save" +msgstr "Αποθήκευση" + +msgid "Subvolume name :" +msgstr "Όνομα υποόγκου :" + +msgid "Select a mount point :" +msgstr "Επιλέξτε ένα σημείο mount :" + +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 "Η χειροκίνητη διαμόρφωση nic χωρίς αυτόματο DHCP απαιτεί μία διεύθυνση 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 "Παρέχει μία επιλογή από περιβάλλοντα επιφάνειας εργασίας και διαχειριστές tiling παραθύρων, π.χ. 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 "Επιλέξτε ποιους διακομιστές να εγκατασταθούν, αν δεν επιλεχθεί κανένας τότε θα γίνει μία minimal εγκατάσταση" + +msgid "Installs a minimal system as well as xorg and graphics drivers." +msgstr "Εγκαθιστά ένα minimal σύστημα καθώς και το 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 "Μπορείτε να παραλείψετε την επιλογή δίσκου και διαμερισμού και να χρησιμοποιήσετε οποιαδήποτε εγκατάσαση δίσκου είναι mount στο /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 "Τύπος bus" + +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 "Παράλληλες Λήψεις" + +#, fuzzy +msgid "ESC to skip" +msgstr "Χρησιμοποιήστε ESC για παράλειψη" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/en/LC_MESSAGES/base.po b/archinstall/locales/en/LC_MESSAGES/base.po index 531e20a9..01f59274 100644 --- a/archinstall/locales/en/LC_MESSAGES/base.po +++ b/archinstall/locales/en/LC_MESSAGES/base.po @@ -232,10 +232,10 @@ msgstr "" msgid "Drive(s)" msgstr "" -msgid "Select disk layout" +msgid "Disk layout" msgstr "" -msgid "Set encryption password" +msgid "Encryption password" msgstr "" msgid "Swap" @@ -244,7 +244,7 @@ msgstr "" msgid "Bootloader" msgstr "" -msgid "root password" +msgid "Root password" msgstr "" msgid "Superuser account" @@ -392,7 +392,7 @@ msgstr "" msgid "Delete" msgstr "" -msgid "Select an action for < {} >" +msgid "Select an action for '{}'" msgstr "" msgid "Copy to new key:" @@ -617,7 +617,7 @@ msgstr "" msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +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." @@ -689,3 +689,92 @@ msgstr "" msgid "Select which partitions to mark for formatting:" msgstr "" + +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +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 "" + +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 "" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +msgid "ESC to skip" +msgstr "" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/es/LC_MESSAGES/base.mo b/archinstall/locales/es/LC_MESSAGES/base.mo Binary files differindex 08b79e92..6006c274 100644 --- a/archinstall/locales/es/LC_MESSAGES/base.mo +++ b/archinstall/locales/es/LC_MESSAGES/base.mo diff --git a/archinstall/locales/es/LC_MESSAGES/base.po b/archinstall/locales/es/LC_MESSAGES/base.po index 58afcbc3..3bdbe72f 100644 --- a/archinstall/locales/es/LC_MESSAGES/base.po +++ b/archinstall/locales/es/LC_MESSAGES/base.po @@ -21,7 +21,7 @@ msgid "Do you really want to abort?" msgstr "¿Realmente desea abortar?" msgid "And one more time for verification: " -msgstr "Una última vez para verificación: " +msgstr "Una vez más para verificar: " msgid "Would you like to use swap on zram?" msgstr "¿Te gustaría usar swap en zram?" @@ -33,7 +33,7 @@ msgid "Username for required superuser with sudo privileges: " msgstr "Nombre de usuario para el superusuario con privilegios sudo: " msgid "Any additional users to install (leave blank for no users): " -msgstr "Algún usuario adicional a instalar (deje en blanco para no agregar ninguno): " +msgstr "Algún usuario adicional a instalar (déjelo en blanco para no agregar ninguno): " msgid "Should this user be a superuser (sudoer)?" msgstr "Debería este usuario ser un superusuario (sudoer)?" @@ -45,10 +45,10 @@ msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" msgstr "Te gustaría usar GRUB como gestor de arranque en lugar de systemd-boot?" msgid "Choose a bootloader" -msgstr "Elige un gestor de arranque" +msgstr "Elija un gestor de arranque" msgid "Choose an audio server" -msgstr "Elige un servidor de audio" +msgstr "Elija un servidor de audio" msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." msgstr "Solo paquetes como base, base-devel, linux, linux-firmware, efibootmgr y paquetes opcionales de perfil se instalan." @@ -66,7 +66,7 @@ msgid "Use NetworkManager (necessary to configure internet graphically in GNOME msgstr "Usar NetworkManager (necesario para configurar internet gráficamente en GNOME y KDE)" msgid "Select one network interface to configure" -msgstr "Selecciona una interfaz de red para configurar" +msgstr "Seleccione una interfaz de red para configurar" msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" msgstr "Seleccione qué modo configurar para \"{}\" o salte para usar el modo predeterminado \"{}\"" @@ -75,13 +75,13 @@ msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " msgstr "Escriba la IP y subred para {} (ejemplo: 192.168.0.5/24): " msgid "Enter your gateway (router) IP address or leave blank for none: " -msgstr "Escriba la IP de su puerta de enlace (enrutador) o deje en blanco para no usar ninguna: " +msgstr "Escriba la IP de su puerta de enlace (enrutador) o déjelo en blanco para no usar ninguna: " msgid "Enter your DNS servers (space separated, blank for none): " -msgstr "Escriba los servidores DNS (separados por espacios, en blanco para no usar ninguno): " +msgstr "Ingrese sus servidores DNS (separados por espacios, en blanco para ninguno): " msgid "Select which filesystem your main partition should use" -msgstr "Selecciona el sistema de archivos que su partición principal debe usar" +msgstr "Seleccione qué sistema de archivos debe usar su partición principal" msgid "Current partition layout" msgstr "Distribución actual de las particiones" @@ -90,17 +90,17 @@ msgid "" "Select what to do with\n" "{}" msgstr "" -"Selecciona qué hacer con\n" +"Seleccione qué hacer con\n" "{}" msgid "Enter a desired filesystem type for the partition" msgstr "Ingrese un tipo de sistema de archivos deseado para la partición" msgid "Enter the start sector (percentage or block number, default: {}): " -msgstr "Escriba el sector de inicio (porcentaje o número de bloque, por defecto: {}): " +msgstr "Introduzca el sector de inicio (porcentaje o número de bloque, predeterminado: {}): " msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " -msgstr "Escriba el sector final de la partición (porcentaje o número de bloque, ej: {}): " +msgstr "Ingrese el sector final de la partición (porcentaje o número de bloque, ej: {}): " msgid "{} contains queued partitions, this will remove those, are you sure?" msgstr "{} contiene particiones en cola, esto eliminará esas particiones, ¿estás seguro?" @@ -112,7 +112,7 @@ msgid "" msgstr "" "{}\n" "\n" -"Selecciona por índice las particiones a eliminar" +"Seleccione por índice qué particiones eliminar" msgid "" "{}\n" @@ -121,13 +121,13 @@ msgid "" msgstr "" "{}\n" "\n" -"Selecciona por índice la ubicación de la partición a montar" +"Seleccione por índice la ubicación de la partición a montar" msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." msgstr " * Los puntos de montaje de partición son relativos a la instalación, el arranque sería /boot como ejemplo." msgid "Select where to mount partition (leave blank to remove mountpoint): " -msgstr "Seleccione dónde montar la partición (deja en blanco para eliminar el punto de montaje): " +msgstr "Seleccione dónde montar la partición (déjelo en blanco para eliminar el punto de montaje): " msgid "" "{}\n" @@ -166,7 +166,7 @@ msgstr "" "Seleccione en qué partición establecer un sistema de archivos" msgid "Enter a desired filesystem type for the partition: " -msgstr "Escriba el tipo de sistema de archivos que desea para la partición: " +msgstr "Ingrese un tipo de sistema de archivos deseado para la partición: " msgid "Archinstall language" msgstr "Idioma de Archinstall" @@ -193,13 +193,13 @@ msgid "Select one or more hard drives to use and configure" msgstr "Seleccione uno o más discos duros para usar y configurar" msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." -msgstr "Para la mejor compatibilidad con tu hardware AMD, puedes querer usar tanto la opción de todo código abierto como la opción AMD / ATI." +msgstr "Para obtener la mejor compatibilidad con su hardware AMD, es posible que desee utilizar las opciones de código abierto o 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 "Para la mejor compatibilidad con tu hardware Intel, puedes querer usar tanto la opción de todo código abierto como la opción Intel.\n" +msgstr "Para obtener la mejor compatibilidad con su hardware Intel, es posible que desee utilizar las opciones de código abierto o de Intel.\n" msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" -msgstr "Para la mejor compatibilidad con tu hardware Nvidia, puedes querer usar el controlador propietario Nvidia.\n" +msgstr "Para obtener la mejor compatibilidad con su hardware de Nvidia, es posible que desee utilizar el controlador patentado de Nvidia.\n" msgid "" "\n" @@ -211,16 +211,16 @@ msgstr "" "Seleccione un controlador de gráficos o déjelo en blanco para instalar todos los controladores de código abierto" msgid "All open-source (default)" -msgstr "Todo de código abierto (predeterminado)" +msgstr "Todos de código abierto (predeterminado)" msgid "Choose which kernels to use or leave blank for default \"{}\"" -msgstr "Elige qué kernels usar o deja en blanco para usar los por defecto \"{}\"" +msgstr "Elija qué kernel usar o déjelo en blanco para usar el kernel \"{}\" predeterminado" msgid "Choose which locale language to use" -msgstr "Elige qué idioma local usar" +msgstr "Elija qué idioma local usar" msgid "Choose which locale encoding to use" -msgstr "Elige qué codificación local usar" +msgstr "Elija qué codificación local usar" msgid "Select one of the values shown below: " msgstr "Seleccione uno de los valores que se muestran a continuación: " @@ -232,7 +232,7 @@ msgid "Adding partition...." msgstr "Añadiendo partición..." msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." -msgstr "Necesitas ingresar un tip de filesystem valido para continuar. Vea `man parted` para tipos de sistemas de archivos válidos." +msgstr "Debe ingresar un tipo de fs válido para continuar. Consulte `man parted` para conocer los tipos de fs válidos." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Error: Enlistar perfiles en la URL \"{}\" resultó en:" @@ -265,7 +265,7 @@ msgid "Swap" msgstr "Swap" msgid "Bootloader" -msgstr "Cargador de arranque" +msgstr "Gestor de arranque" msgid "Root password" msgstr "Contraseña de root" @@ -423,8 +423,8 @@ msgstr "Editar" msgid "Delete" msgstr "Eliminar" -msgid "Select an action for < {} >" -msgstr "Seleccione una acción para < {} >" +msgid "Select an action for '{}'" +msgstr "Seleccione una acción para '{}'" msgid "Copy to new key:" msgstr "Copiar a nueva clave:" @@ -657,7 +657,8 @@ msgstr "Una instalación muy básica que te permite personalizar Arch Linux como msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Proporciona una selección de varios paquetes de servidor para instalar y habilitar, p.e. httpd, nginx, mariadb" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +#, fuzzy +msgid "Choose which servers to install, if none then a minimal installation will be done" msgstr "Elija qué servidores instalar, si no hay ninguno, se realizará una instalación mínima" msgid "Installs a minimal system as well as xorg and graphics drivers." @@ -761,6 +762,71 @@ 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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Subvolumen :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Eliminar usuario" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Use ESC para saltar" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + #~ msgid "Select disk layout" #~ msgstr "Seleccione el diseño del disco" diff --git a/archinstall/locales/fr/LC_MESSAGES/base.mo b/archinstall/locales/fr/LC_MESSAGES/base.mo Binary files differindex 918fe21d..b8f19aa7 100644 --- a/archinstall/locales/fr/LC_MESSAGES/base.mo +++ b/archinstall/locales/fr/LC_MESSAGES/base.mo diff --git a/archinstall/locales/fr/LC_MESSAGES/base.po b/archinstall/locales/fr/LC_MESSAGES/base.po index 9b038e8c..f85c9e25 100644 --- a/archinstall/locales/fr/LC_MESSAGES/base.po +++ b/archinstall/locales/fr/LC_MESSAGES/base.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" -"Last-Translator: Aleksandr Melman <Alexmelman88@gmail.com>\n" +"Last-Translator: roxfr <roxfr@outlook.fr>\n" "Language-Team: \n" "Language: fr\n" "MIME-Version: 1.0\n" @@ -255,13 +255,11 @@ msgstr "Encodage des paramètres régionaux" msgid "Drive(s)" msgstr "Disques durs" -#, fuzzy msgid "Disk layout" -msgstr "Enregistrer la disposition du disque" +msgstr "Disposition du disque" -#, fuzzy msgid "Encryption password" -msgstr "Définir le mot de passe de chiffrement" +msgstr "Mot de passe de cryptage" msgid "Swap" msgstr "Swap" @@ -269,7 +267,6 @@ msgstr "Swap" msgid "Bootloader" msgstr "Chargeur de démarrage" -#, fuzzy msgid "Root password" msgstr "Mot de passe root" @@ -428,8 +425,8 @@ msgstr "Modifier" msgid "Delete" msgstr "Supprimer" -msgid "Select an action for < {} >" -msgstr "Sélectionner une action pour < {} >" +msgid "Select an action for '{}'" +msgstr "Sélectionner une action pour '{}'" msgid "Copy to new key:" msgstr "Copier vers une nouvelle clé :" @@ -548,7 +545,7 @@ msgid "Manage ordinary user accounts: " msgstr "Gérer les comptes d'utilisateurs ordinaires : " msgid " Subvolume :{:16}" -msgstr " Sous-volume :{:16}" +msgstr " Sous-volume : {:16}" msgid " mounted at {:16}" msgstr " monté à {:16}" @@ -662,7 +659,8 @@ msgstr "Une installation très basique qui vous permet de personnaliser Arch Lin msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Fournit une sélection de divers paquets de serveur à installer et à activer, par ex. httpd, nginx, mariadb" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +#, fuzzy +msgid "Choose which servers to install, if none then a minimal installation will be done" msgstr "Choisir les serveurs à installer, s'il n'y en a pas, une installation minimale sera effectuée" msgid "Installs a minimal system as well as xorg and graphics drivers." @@ -713,16 +711,16 @@ msgstr "" "\n" msgid "Copy to: " -msgstr "Copier vers: " +msgstr "Copier vers : " msgid "Edit: " -msgstr "Modifier: " +msgstr "Modifier : " msgid "Key: " -msgstr "Clé: " +msgstr "Clé : " msgid "Edit {}: " -msgstr "Modifier {}: " +msgstr "Modifier {} : " msgid "Add: " msgstr "Ajouter: " @@ -731,14 +729,110 @@ msgid "Value: " msgstr "Valeur: " msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" -msgstr "" +msgstr "Vous pouvez ignorer la sélection d'un lecteur et le partitionnement et utiliser n'importe quelle configuration de lecteur montée sur /mnt (expérimental)" msgid "Select one of the disks or skip and use /mnt as default" -msgstr "" +msgstr "Sélectionner l'un des disques ou ignorer et utiliser /mnt par défaut" msgid "Select which partitions to mark for formatting:" msgstr "Sélectionner la partition à masquer pour le formatage:" +msgid "Use HSM to unlock encrypted drive" +msgstr "Utiliser HSM pour déverrouiller le lecteur chiffré" + +msgid "Device" +msgstr "Dispositif" + +msgid "Size" +msgstr "Taille" + +msgid "Free space" +msgstr "Espace libre" + +msgid "Bus-type" +msgstr "Type de bus" + +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Le mot de passe root ou au moins 1 utilisateur avec des privilèges sudo doit être spécifié" + +msgid "Enter username (leave blank to skip): " +msgstr "Entrer le nom d'utilisateur (laisser vide pour passer) :" + +msgid "The username you entered is invalid. Try again" +msgstr "Le nom d'utilisateur que vous avez saisi n'est pas valide. Réessayer" + +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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Sous-volume : {:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Supprimer l'utilisateur" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Utiliser ESC pour ignorer" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + #~ msgid "Select disk layout" #~ msgstr "Sélectionner la disposition du disque" diff --git a/archinstall/locales/id/LC_MESSAGES/base.mo b/archinstall/locales/id/LC_MESSAGES/base.mo Binary files differnew file mode 100644 index 00000000..c02df9eb --- /dev/null +++ b/archinstall/locales/id/LC_MESSAGES/base.mo diff --git a/archinstall/locales/id/LC_MESSAGES/base.po b/archinstall/locales/id/LC_MESSAGES/base.po new file mode 100644 index 00000000..0ace1b09 --- /dev/null +++ b/archinstall/locales/id/LC_MESSAGES/base.po @@ -0,0 +1,832 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Ali Rohman <laymoth@pm.me>\n" +"Language-Team: \n" +"Language: id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.1\n" + +msgid "[!] A log file has been created here: {} {}" +msgstr "[!] File log telah dibuat di sini: {} {}" + +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " Silakan kirimkan masalah ini (dan file) ke https://github.com/archlinux/archinstall/issues" + +msgid "Do you really want to abort?" +msgstr "Apakah Anda benar-benar ingin membatalkan?" + +msgid "And one more time for verification: " +msgstr "Dan sekali lagi untuk verifikasi: " + +msgid "Would you like to use swap on zram?" +msgstr "Apakah Anda ingin menggunakan swap di zram?" + +msgid "Desired hostname for the installation: " +msgstr "Nama host yang diinginkan untuk instalasi: " + +msgid "Username for required superuser with sudo privileges: " +msgstr "Nama pengguna untuk superuser yang diperlukan dengan hak sudo: " + +msgid "Any additional users to install (leave blank for no users): " +msgstr "Beberapa pengguna tambahan untuk dipasang (biarkan kosong untuk tidak menambahkan): " + +msgid "Should this user be a superuser (sudoer)?" +msgstr "Haruskah pengguna ini menjadi superuser (sudoer)?" + +msgid "Select a timezone" +msgstr "Pilih zona waktu" + +msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" +msgstr "Apakah Anda ingin menggunakan GRUB sebagai bootloader daripada systemd-boot?" + +msgid "Choose a bootloader" +msgstr "Pilih bootloader" + +msgid "Choose an audio server" +msgstr "Pilih server audio" + +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "Hanya paket seperti base, base-devel, linux, linux-firmware, efibootmgr dan paket profil opsional yang diinstal." + +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Jika Anda menginginkan web browser, seperti firefox atau chromium, Anda dapat menentukannya di prompt berikut." + +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "Ketik paket tambahan untuk diinstal (dipisahkan dengan spasi, biarkan kosong untuk dilewati): " + +msgid "Copy ISO network configuration to installation" +msgstr "Salin konfigurasi jaringan ISO ke instalasi" + +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Gunakan NetworkManager (diperlukan untuk mengkonfigurasi internet secara grafis di GNOME dan KDE)" + +msgid "Select one network interface to configure" +msgstr "Pilih satu interface jaringan untuk dikonfigurasi" + +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "Pilih mode mana yang akan dikonfigurasi untuk \"{}\" atau lewati untuk menggunakan mode default \"{}\"" + +msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " +msgstr "Masukkan IP dan subnet untuk {} (contoh: 192.168.0.5/24): " + +msgid "Enter your gateway (router) IP address or leave blank for none: " +msgstr "Masukkan IP gateway (router) Anda atau biarkan kosong untuk tidak menggunakan apa pun: " + +msgid "Enter your DNS servers (space separated, blank for none): " +msgstr "Masukkan server DNS Anda (dipisahkan dengan spasi, untuk kosongkan tidak menggunakan apa pun): " + +msgid "Select which filesystem your main partition should use" +msgstr "Pilih filesystem mana yang harus digunakan partisi utama Anda" + +msgid "Current partition layout" +msgstr "Tata letak partisi saat ini" + +msgid "" +"Select what to do with\n" +"{}" +msgstr "" +"Pilih apa yang harus dilakukan dengan\n" +"{}" + +msgid "Enter a desired filesystem type for the partition" +msgstr "Masukkan jenis filesystem yang diinginkan untuk partisi" + +msgid "Enter the start sector (percentage or block number, default: {}): " +msgstr "Masukkan sektor awal (persentase atau nomor blok, default: {}): " + +msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " +msgstr "Masukkan sektor akhir partisi (persentase atau nomor blok, mis: {}): " + +msgid "{} contains queued partitions, this will remove those, are you sure?" +msgstr "{} berisi partisi yang mengantri, ini akan menghapusnya, apakah Anda yakin?" + +msgid "" +"{}\n" +"\n" +"Select by index which partitions to delete" +msgstr "" +"{}\n" +"\n" +"Pilih berdasarkan indeks partisi mana yang akan dihapus" + +msgid "" +"{}\n" +"\n" +"Select by index which partition to mount where" +msgstr "" +"{}\n" +"\n" +"Pilih berdasarkan indeks partisi mana yang akan di mount" + +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Mount point partisi relatif terhadap di dalam instalasi, boot akan menjadi /boot sebagai contoh." + +msgid "Select where to mount partition (leave blank to remove mountpoint): " +msgstr "Pilih tempat untuk memasang partisi (biarkan kosong untuk menghapus mountpoint): " + +msgid "" +"{}\n" +"\n" +"Select which partition to mask for formatting" +msgstr "" +"{}\n" +"\n" +"Pilih partisi mana yang akan di mask untuk pemformatan" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as encrypted" +msgstr "" +"{}\n" +"\n" +"Pilih partisi mana yang akan ditandai sebagai terenkripsi" + +msgid "" +"{}\n" +"\n" +"Select which partition to mark as bootable" +msgstr "" +"{}\n" +"\n" +"Pilih partisi mana yang akan ditandai sebagai bootable" + +msgid "" +"{}\n" +"\n" +"Select which partition to set a filesystem on" +msgstr "" +"{}\n" +"\n" +"Pilih partisi mana untuk mengatur sistem file" + +msgid "Enter a desired filesystem type for the partition: " +msgstr "Masukkan jenis filesystem yang diinginkan untuk partisi: " + +msgid "Archinstall language" +msgstr "Bahasa Archinstall" + +msgid "Wipe all selected drives and use a best-effort default partition layout" +msgstr "Hapus semua drive yang dipilih dan gunakan upaya terbaik tata letak partisi default" + +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "Pilih apa yang harus dilakukan dengan setiap drive individu (diikuti dengan penggunaan partisi)" + +msgid "Select what you wish to do with the selected block devices" +msgstr "Pilih apa yang ingin Anda lakukan dengan perangkat blok yang dipilih" + +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "Ini adalah daftar profil yang telah diprogram sebelumnya, mereka mungkin memudahkan untuk menginstal hal-hal seperti desktop environment" + +msgid "Select keyboard layout" +msgstr "Pilih tata letak keyboard" + +msgid "Select one of the regions to download packages from" +msgstr "Pilih salah satu wilayah untuk mengunduh paket dari mana" + +msgid "Select one or more hard drives to use and configure" +msgstr "Pilih satu atau lebih hard drive untuk digunakan dan dikonfigurasi" + +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "Untuk kompatibilitas terbaik dengan perangkat keras AMD Anda, Anda mungkin ingin menggunakan opsi semua sumber terbuka atau 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 "Untuk kompatibilitas terbaik dengan perangkat keras Intel Anda, Anda mungkin ingin menggunakan opsi semua sumber terbuka atau Intel.\n" + +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Untuk kompatibilitas terbaik dengan perangkat keras Nvidia Anda, Anda mungkin ingin menggunakan driver proprietary Nvidia.\n" + +msgid "" +"\n" +"\n" +"Select a graphics driver or leave blank to install all open-source drivers" +msgstr "" +"\n" +"\n" +"Pilih driver grafis atau biarkan kosong untuk menginstal semua driver open-source" + +msgid "All open-source (default)" +msgstr "Semua sumber terbuka (default)" + +msgid "Choose which kernels to use or leave blank for default \"{}\"" +msgstr "Pilih kernel mana yang akan digunakan atau biarkan kosong untuk \"{}\" default" + +msgid "Choose which locale language to use" +msgstr "Pilih locale bahasa yang akan digunakan" + +msgid "Choose which locale encoding to use" +msgstr "Pilih locale encoding yang akan digunakan" + +msgid "Select one of the values shown below: " +msgstr "Pilih salah satu nilai yang ditunjukkan di bawah ini: " + +msgid "Select one or more of the options below: " +msgstr "Pilih satu atau beberapa opsi di bawah ini: " + +msgid "Adding partition...." +msgstr "Menambahkan partisi...." + +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Anda harus memasukkan tipe fs yang valid untuk melanjutkan. Lihat `man parted` untuk tipe fs yang valid." + +msgid "Error: Listing profiles on URL \"{}\" resulted in:" +msgstr "Kesalahan: Mencantumkan profil pada URL \"{}\" mengakibatkan:" + +msgid "Error: Could not decode \"{}\" result as JSON:" +msgstr "Kesalahan: Tidak dapat mendekode hasil \"{}\" sebagai JSON:" + +msgid "Keyboard layout" +msgstr "Tata letak keyboard" + +msgid "Mirror region" +msgstr "Wilayah mirror" + +msgid "Locale language" +msgstr "Locale language" + +msgid "Locale encoding" +msgstr "Locale encoding" + +msgid "Drive(s)" +msgstr "Drive" + +msgid "Disk layout" +msgstr "Tata letak disk" + +msgid "Encryption password" +msgstr "Kata sandi enkripsi" + +msgid "Swap" +msgstr "Swap" + +msgid "Bootloader" +msgstr "Bootloader" + +msgid "Root password" +msgstr "Kata sandi root" + +msgid "Superuser account" +msgstr "Akun superuser" + +msgid "User account" +msgstr "Akun pengguna" + +msgid "Profile" +msgstr "Profil" + +msgid "Audio" +msgstr "Audio" + +msgid "Kernels" +msgstr "Kernel" + +msgid "Additional packages" +msgstr "Paket tambahan" + +msgid "Network configuration" +msgstr "Konfigurasi jaringan" + +msgid "Automatic time sync (NTP)" +msgstr "Sinkronisasi waktu otomatis (NTP)" + +msgid "Install ({} config(s) missing)" +msgstr "Instal ({} konfigurasi tidak ada)" + +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 "" +"Anda memutuskan untuk melewati pemilihan harddisk\n" +"dan akan menggunakan pengaturan drive apa pun yang dipasang di {} (eksperimental)\n" +"PERINGATAN: Archinstall tidak akan memeriksa kesesuaian pengaturan ini\n" +"Apakah Anda ingin melanjutkan?" + +msgid "Re-using partition instance: {}" +msgstr "Menggunakan kembali instance partisi: {}" + +msgid "Create a new partition" +msgstr "Buat partisi baru" + +msgid "Delete a partition" +msgstr "Hapus partisi" + +msgid "Clear/Delete all partitions" +msgstr "Bersihkan/Hapus semua partisi" + +msgid "Assign mount-point for a partition" +msgstr "Tetapkan titik-mount untuk sebuah partisi" + +msgid "Mark/Unmark a partition to be formatted (wipes data)" +msgstr "Tandai/Hapus tanda partisi yang akan diformat (menghapus data)" + +msgid "Mark/Unmark a partition as encrypted" +msgstr "Tandai/Hapus tanda partisi sebagai terenkripsi" + +msgid "Mark/Unmark a partition as bootable (automatic for /boot)" +msgstr "Tandai/Hapus tanda partisi sebagai bootable (otomatis untuk /boot)" + +msgid "Set desired filesystem for a partition" +msgstr "Atur filesystem yang diinginkan untuk sebuah partisi" + +msgid "Abort" +msgstr "Batalkan" + +msgid "Hostname" +msgstr "Hostname" + +msgid "Not configured, unavailable unless setup manually" +msgstr "Tidak dikonfigurasi, tidak tersedia kecuali diatur secara manual" + +msgid "Timezone" +msgstr "Zona waktu" + +msgid "Set/Modify the below options" +msgstr "Atur/Ubah opsi di bawah ini" + +msgid "Install" +msgstr "Install" + +msgid "" +"Use ESC to skip\n" +"\n" +msgstr "" +"Gunakan ESC untuk melewati\n" +"\n" + +msgid "Suggest partition layout" +msgstr "Saran tata letak partisi" + +msgid "Enter a password: " +msgstr "Masukan kata sandi: " + +msgid "Enter a encryption password for {}" +msgstr "Masukkan sandi enkripsi untuk {}" + +msgid "Enter disk encryption password (leave blank for no encryption): " +msgstr "Masukkan kata sandi enkripsi disk (biarkan kosong jika tidak ada enkripsi): " + +msgid "Create a required super-user with sudo privileges: " +msgstr "Buat pengguna super yang diperlukan dengan hak sudo: " + +msgid "Enter root password (leave blank to disable root): " +msgstr "Masukkan kata sandi root (biarkan kosong untuk menonaktifkan root): " + +msgid "Password for user \"{}\": " +msgstr "Kata sandi untuk pengguna \"{}\": " + +msgid "Verifying that additional packages exist (this might take a few seconds)" +msgstr "Memverifikasi bahwa ada paket tambahan (ini mungkin memakan waktu beberapa detik)" + +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "Apakah Anda ingin menggunakan sinkronisasi waktu otomatis (NTP) dengan server waktu default?\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 "" +"Waktu perangkat keras dan langkah-langkah pasca-konfigurasi lainnya mungkin diperlukan agar NTP berfungsi.\n" +"Untuk informasi lebih lanjut, silakan periksa Arch wiki" + +msgid "Enter a username to create an additional user (leave blank to skip): " +msgstr "Masukkan nama pengguna untuk membuat pengguna tambahan (biarkan kosong untuk melewati): " + +msgid "Use ESC to skip\n" +msgstr "Gunakan ESC untuk melewati\n" + +msgid "" +"\n" +" Choose an object from the list, and select one of the available actions for it to execute" +msgstr "" +"\n" +"Pilih objek dari daftar, dan pilih salah satu tindakan yang tersedia untuk dieksekusi" + +msgid "Cancel" +msgstr "Batalkan" + +msgid "Confirm and exit" +msgstr "Konfirmasi dan keluar" + +msgid "Add" +msgstr "Tambah" + +msgid "Copy" +msgstr "Salin" + +msgid "Edit" +msgstr "Edit" + +msgid "Delete" +msgstr "Hapus" + +msgid "Select an action for '{}'" +msgstr "Pilih tindakan untuk '{}'" + +msgid "Copy to new key:" +msgstr "Salin ke kunci baru:" + +msgid "Unknown nic type: {}. Possible values are {}" +msgstr "Jenis nic tidak dikenal: {}. Nilai yang mungkin adalah {}" + +msgid "" +"\n" +"This is your chosen configuration:" +msgstr "" +"\n" +"Ini adalah konfigurasi yang Anda pilih:" + +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman sudah berjalan, menunggu maksimal 10 menit untuk berhenti." + +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "Pacman lock yang sudah ada tidak pernah keluar. Harap bersihkan sesi pacman yang ada sebelum menggunakan archinstall." + +msgid "Choose which optional additional repositories to enable" +msgstr "Pilih repositori tambahan opsional mana yang akan diaktifkan" + +msgid "Add a user" +msgstr "Tambahkan pengguna" + +msgid "Change password" +msgstr "Ganti kata sandi" + +msgid "Promote/Demote user" +msgstr "Promosikan/Turunkan pengguna" + +msgid "Delete User" +msgstr "Hapus pengguna" + +msgid "" +"\n" +"Define a new user\n" +msgstr "" +"\n" +"Tentukan pengguna baru\n" + +msgid "User Name : " +msgstr "Nama Pengguna : " + +msgid "Should {} be a superuser (sudoer)?" +msgstr "Haruskah {} menjadi superuser (sudoer)?" + +msgid "Define users with sudo privilege: " +msgstr "Tentukan pengguna dengan hak sudo: " + +msgid "No network configuration" +msgstr "Tidak ada konfigurasi jaringan" + +msgid "Set desired subvolumes on a btrfs partition" +msgstr "Atur subvolume yang diinginkan pada partisi btrfs" + +msgid "" +"{}\n" +"\n" +"Select which partition to set subvolumes on" +msgstr "" +"{}\n" +"\n" +"Pilih partisi mana untuk mengatur subvolume" + +msgid "Manage btrfs subvolumes for current partition" +msgstr "Kelola subvolume btrfs untuk partisi saat ini" + +msgid "No configuration" +msgstr "Tidak ada konfigurasi" + +msgid "Save user configuration" +msgstr "Simpan konfigurasi pengguna" + +msgid "Save user credentials" +msgstr "Simpan kredensial pengguna" + +msgid "Save disk layout" +msgstr "Simpan tata letak disk" + +msgid "Save all" +msgstr "Simpan semua" + +msgid "Choose which configuration to save" +msgstr "Pilih konfigurasi mana yang akan disimpan" + +msgid "Enter a directory for the configuration(s) to be saved: " +msgstr "Masukkan direktori untuk konfigurasi yang akan disimpan: " + +msgid "Not a valid directory: {}" +msgstr "Bukan direktori yang valid: {}" + +msgid "The password you are using seems to be weak," +msgstr "Kata sandi yang Anda gunakan tampaknya lemah," + +msgid "are you sure you want to use it?" +msgstr "apakah Anda yakin ingin menggunakannya?" + +msgid "Optional repositories" +msgstr "Repositori opsional" + +msgid "Save configuration" +msgstr "Simpan konfigurasi" + +msgid "Missing configurations:\n" +msgstr "Konfigurasi tidak ada: \n" + +msgid "Either root-password or at least 1 superuser must be specified" +msgstr "Salah satu root-password atau setidaknya 1 superuser harus ditentukan" + +msgid "Manage superuser accounts: " +msgstr "Kelola akun superuser: " + +msgid "Manage ordinary user accounts: " +msgstr "Kelola akun pengguna biasa: " + +msgid " Subvolume :{:16}" +msgstr " Subvolume :{:16}" + +msgid " mounted at {:16}" +msgstr " di mount di {:16}" + +msgid " with option {}" +msgstr " dengan opsi {}" + +msgid "" +"\n" +" Fill the desired values for a new subvolume \n" +msgstr "" +"\n" +"Isi nilai yang diinginkan untuk subvolume baru\n" + +msgid "Subvolume name " +msgstr " Nama subvolume" + +msgid "Subvolume mountpoint" +msgstr "Titik mount subvolume" + +msgid "Subvolume options" +msgstr "Opsi subvolume" + +msgid "Save" +msgstr "Simpan" + +msgid "Subvolume name :" +msgstr "Nama subvolume :" + +msgid "Select a mount point :" +msgstr "Pilih titik mount :" + +msgid "Select the desired subvolume options " +msgstr "Pilih opsi subvolume yang diinginkan " + +msgid "Define users with sudo privilege, by username: " +msgstr "Tentukan pengguna dengan hak sudo, berdasarkan nama pengguna: " + +msgid "[!] A log file has been created here: {}" +msgstr "[!] File log telah dibuat di sini: {}" + +msgid "Would you like to use BTRFS subvolumes with a default structure?" +msgstr "Apakah Anda ingin menggunakan subvolume BTRFS dengan struktur default?" + +msgid "Would you like to use BTRFS compression?" +msgstr "Apakah Anda ingin menggunakan kompresi BTRFS?" + +msgid "Would you like to create a separate partition for /home?" +msgstr "Apakah Anda ingin membuat partisi terpisah untuk /home?" + +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "Drive yang dipilih tidak memiliki kapasitas minimum yang diperlukan untuk saran otomatis\n" + +msgid "Minimum capacity for /home partition: {}GB\n" +msgstr "Kapasitas minimum untuk partisi /home: {}GB\n" + +msgid "Minimum capacity for Arch Linux partition: {}GB" +msgstr "Kapasitas minimum untuk partisi Arch Linux: {}GB" + +msgid "Continue" +msgstr "Lanjutkan" + +msgid "yes" +msgstr "ya" + +msgid "no" +msgstr "tidak" + +msgid "set: {}" +msgstr "atur: {}" + +msgid "Manual configuration setting must be a list" +msgstr "Pengaturan konfigurasi manual harus berupa list" + +msgid "No iface specified for manual configuration" +msgstr "Tidak ada iface yang ditentukan untuk konfigurasi manual" + +msgid "Manual nic configuration with no auto DHCP requires an IP address" +msgstr "Konfigurasi nic manual tanpa DHCP otomatis memerlukan alamat IP" + +msgid "Add interface" +msgstr "Tambahkan interface" + +msgid "Edit interface" +msgstr "Edit interface" + +msgid "Delete interface" +msgstr "Hapus interface" + +msgid "Select interface to add" +msgstr "Pilih interface untuk ditambahkan" + +msgid "Manual configuration" +msgstr "Konfigurasi manual" + +msgid "Mark/Unmark a partition as compressed (btrfs only)" +msgstr "Tandai/Hapus tanda partisi sebagai terkompresi (hanya btrfs)" + +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "Kata sandi yang Anda gunakan tampaknya lemah, apakah Anda yakin ingin menggunakannya?" + +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "Menyediakan pilihan desktop environment dan tiling window manager, cth. gnome, kde, sway" + +msgid "Select your desired desktop environment" +msgstr "Pilih desktop environment yang Anda inginkan" + +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Instalasi yang sangat basic yang memungkinkan Anda untuk menyesuaikan Arch Linux sesuai keinginan Anda." + +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "Menyediakan pilihan berbagai paket server untuk diinstal dan diaktifkan, cth. httpd, nginx, mariadb" + +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Pilih server mana yang akan diinstal, jika tidak ada maka instalasi minimal akan dilakukan" + +msgid "Installs a minimal system as well as xorg and graphics drivers." +msgstr "Install sistem minimal serta xorg dan driver grafis." + +msgid "Press Enter to continue." +msgstr "Tekan Enter untuk melanjutkan." + +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "Apakah Anda ingin melakukan chroot ke instalasi yang baru dibuat dan melakukan konfigurasi pasca-instalasi?" + +msgid "Are you sure you want to reset this setting?" +msgstr "Anda yakin ingin menyetel ulang setelan ini?" + +msgid "Select one or more hard drives to use and configure\n" +msgstr "Pilih satu atau lebih hard drive untuk digunakan dan dikonfigurasi\n" + +msgid "Any modifications to the existing setting will reset the disk layout!" +msgstr "Setiap modifikasi pada pengaturan yang ada akan mengatur ulang tata letak disk!" + +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "Jika Anda mengatur ulang pilihan harddrive, ini juga akan mengatur ulang tata letak disk saat ini. Apakah Anda yakin?" + +msgid "Save and exit" +msgstr "Simpan dan keluar" + +msgid "" +"{}\n" +"contains queued partitions, this will remove those, are you sure?" +msgstr "" +"{}\n" +"berisi partisi yang mengantri, ini akan menghapusnya, apakah Anda yakin?" + +msgid "No audio server" +msgstr "Tidak ada server audio" + +msgid "(default)" +msgstr "(default)" + +msgid "Use ESC to skip" +msgstr "Gunakan ESC untuk melewati" + +msgid "" +"Use CTRL+C to reset current selection\n" +"\n" +msgstr "" +"Gunakan CTRL + C untuk mengatur ulang pilihan saat ini\n" +"\n" + +msgid "Copy to: " +msgstr "Salin ke: " + +msgid "Edit: " +msgstr "Edit: " + +msgid "Key: " +msgstr "Kunci: " + +msgid "Edit {}: " +msgstr "Edit {}: " + +msgid "Add: " +msgstr "Tambah: " + +msgid "Value: " +msgstr "Nilai: " + +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "Anda dapat melewatkan memilih drive dan mempartisi dan menggunakan pengaturan drive apa pun yang dipasang di /mnt (eksperimental)" + +msgid "Select one of the disks or skip and use /mnt as default" +msgstr "Pilih salah satu disk atau lewati dan gunakan /mnt sebagai default" + +msgid "Select which partitions to mark for formatting:" +msgstr "Pilih partisi mana yang akan ditandai untuk pemformatan:" + +msgid "Use HSM to unlock encrypted drive" +msgstr "Gunakan HSM untuk membuka kunci drive terenkripsi" + +msgid "Device" +msgstr "Perangkat" + +msgid "Size" +msgstr "Ukuran" + +msgid "Free space" +msgstr "Ruang kosong" + +msgid "Bus-type" +msgstr "Tipe bus" + +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Baik kata sandi root atau setidaknya 1 pengguna dengan hak sudo harus ditentukan" + +msgid "Enter username (leave blank to skip): " +msgstr " Masukkan nama pengguna (kosongkan untuk melewati):" + +msgid "The username you entered is invalid. Try again" +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 "very weak" +msgstr "sangat lemah" + +msgid "weak" +msgstr "lemah" + +msgid "moderate" +msgstr "sedang" + +msgid "strong" +msgstr "kuat" + +msgid "Add subvolume" +msgstr "Tambah subvolume" + +msgid "Edit subvolume" +msgstr "Edit subvolume" + +msgid "Delete subvolume" +msgstr "Hapus subvolume" + +msgid "Configured {} interfaces" +msgstr "Interface {} dikonfigurasi" + +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "Opsi ini memungkinkan jumlah unduhan paralel yang dapat terjadi selama instalasi" + +#, 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 "" +"Masukkan jumlah unduhan paralel yang akan diaktifkan.\n" +" (Masukkan nilai antara 1 hingga {max_downloads})\n" +"Catatan:" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - Nilai maksimum : {max_downloads} ( Memungkinkan {max_downloads} unduhan paralel, memungkinkan {max_downloads+1} unduhan sekaligus)" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - Nilai minimum : 1 (Mengizinkan 1 unduhan paralel, memungkinkan 2 unduhan sekaligus)" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr " - Nonaktifkan/Default: 0 (Menonaktifkan pengunduhan paralel, hanya mengizinkan 1 unduhan pada satu waktu)" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "Input tidak valid! Coba lagi dengan input yang valid [1 untuk {max_downloads}, atau 0 untuk menonaktifkan]" + +msgid "Parallel Downloads" +msgstr "Unduhan Paralel" + +msgid "ESC to skip" +msgstr "ESC untuk melewati" + +msgid "CTRL+C to reset" +msgstr "CTRL + C untuk mengatur ulang" + +msgid "TAB to select" +msgstr "TAB untuk memilih" + +msgid "[Default value: 0] > " +msgstr "[Nilai default: 0] > " diff --git a/archinstall/locales/it/LC_MESSAGES/base.mo b/archinstall/locales/it/LC_MESSAGES/base.mo Binary files differindex 34a6c898..c6d984c3 100644 --- a/archinstall/locales/it/LC_MESSAGES/base.mo +++ b/archinstall/locales/it/LC_MESSAGES/base.mo diff --git a/archinstall/locales/it/LC_MESSAGES/base.po b/archinstall/locales/it/LC_MESSAGES/base.po index 36e8d5b4..905ad7cf 100644 --- a/archinstall/locales/it/LC_MESSAGES/base.po +++ b/archinstall/locales/it/LC_MESSAGES/base.po @@ -425,8 +425,8 @@ msgstr "Modifica" msgid "Delete" msgstr "Elimina" -msgid "Select an action for < {} >" -msgstr "Seleziona un'azione per < {} >" +msgid "Select an action for '{}'" +msgstr "Seleziona un'azione per '{}'" msgid "Copy to new key:" msgstr "Copia su nuova chiave:" @@ -659,7 +659,8 @@ msgstr "Un'installazione molto semplice che ti consente di personalizzare Arch L msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Fornisce una selezione di vari pacchetti server da installare e abilitare, per esempio httpd, nginx, mariadb" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +#, fuzzy +msgid "Choose which servers to install, if none then a minimal installation will be done" msgstr "Scegli quali server installare, se nessuno verrà eseguita un'installazione minima" msgid "Installs a minimal system as well as xorg and graphics drivers." @@ -750,3 +751,87 @@ msgstr "Spazio libero" msgid "Bus-type" msgstr "Tipo di bus" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "È necessario specificare la password di root o almeno 1 superuser" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Inserisci un nome utente per creare un utente aggiuntivo (lascia vuoto per saltare): " + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +msgid "Should \"{}\" be a superuser (sudo)?" +msgstr "{} dovrebbe essere un superutente? (sudoer)" + +#, fuzzy +msgid "Select which partitions to encrypt:" +msgstr "" +"{}\n" +"\n" +"Seleziona quale partizione contrassegnare come crittografata" + +msgid "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Sottovolume :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Elimina utente" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Usa ESC per saltare" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/languages.json b/archinstall/locales/languages.json index c649e346..7bee29db 100644 --- a/archinstall/locales/languages.json +++ b/archinstall/locales/languages.json @@ -20,7 +20,7 @@ {"abbr": "br", "lang": "Breton"}, {"abbr": "bg", "lang": "Bulgarian"}, {"abbr": "ca", "lang": "Catalan"}, - {"abbr": "cs", "lang": "Czech"}, + {"abbr": "cs", "lang": "Czech", "translated_lang": "čeština"}, {"abbr": "ch", "lang": "Chamorro"}, {"abbr": "ce", "lang": "Chechen"}, {"abbr": "cu", "lang": "Church Slavic"}, @@ -29,11 +29,11 @@ {"abbr": "co", "lang": "Corsican"}, {"abbr": "cr", "lang": "Cree"}, {"abbr": "cy", "lang": "Welsh"}, - {"abbr": "da", "lang": "Danish"}, - {"abbr": "de", "lang": "German"}, + {"abbr": "da", "lang": "Danish", "translated_lang": "Dansk"}, + {"abbr": "de", "lang": "German", "translated_lang": "Deutsch"}, {"abbr": "dv", "lang": "Dhivehi"}, {"abbr": "dz", "lang": "Dzongkha"}, - {"abbr": "el", "lang": "Modern Greek (1453-)"}, + {"abbr": "el", "lang": "Modern Greek (1453-)", "translated_lang": "Ελληνικά"}, {"abbr": "en", "lang": "English"}, {"abbr": "eo", "lang": "Esperanto"}, {"abbr": "et", "lang": "Estonian"}, @@ -43,7 +43,7 @@ {"abbr": "fa", "lang": "Persian"}, {"abbr": "fj", "lang": "Fijian"}, {"abbr": "fi", "lang": "Finnish"}, - {"abbr": "fr", "lang": "French"}, + {"abbr": "fr", "lang": "French", "translated_lang": "Française"}, {"abbr": "fy", "lang": "Western Frisian"}, {"abbr": "ff", "lang": "Fulah"}, {"abbr": "gd", "lang": "Scottish Gaelic"}, @@ -68,10 +68,10 @@ {"abbr": "iu", "lang": "Inuktitut"}, {"abbr": "ie", "lang": "Interlingue"}, {"abbr": "ia", "lang": "Interlingua (International Auxiliary Language Association)"}, - {"abbr": "id", "lang": "Indonesian"}, + {"abbr": "id", "lang": "Indonesian", "translated_lang": "Indonesia"}, {"abbr": "ik", "lang": "Inupiaq"}, {"abbr": "is", "lang": "Icelandic"}, - {"abbr": "it", "lang": "Italian"}, + {"abbr": "it", "lang": "Italian", "translated_lang": "Italiano"}, {"abbr": "jv", "lang": "Javanese"}, {"abbr": "ja", "lang": "Japanese"}, {"abbr": "kl", "lang": "Kalaallisut"}, @@ -114,7 +114,7 @@ {"abbr": "nd", "lang": "North Ndebele"}, {"abbr": "ng", "lang": "Ndonga"}, {"abbr": "ne", "lang": "Nepali (macrolanguage)"}, - {"abbr": "nl", "lang": "Dutch"}, + {"abbr": "nl", "lang": "Dutch", "translated_lang": "Nederlands"}, {"abbr": "nn", "lang": "Norwegian Nynorsk"}, {"abbr": "nb", "lang": "Norwegian Bokmål"}, {"abbr": "no", "lang": "Norwegian"}, @@ -126,14 +126,15 @@ {"abbr": "os", "lang": "Ossetian"}, {"abbr": "pa", "lang": "Panjabi"}, {"abbr": "pi", "lang": "Pali"}, - {"abbr": "pl", "lang": "Polish"}, - {"abbr": "pt", "lang": "Portuguese"}, + {"abbr": "pl", "lang": "Polish", "translated_lang": "Polskie"}, + {"abbr": "pt", "lang": "Portuguese", "translated_lang": "Português"}, + {"abbr": "pt_BR", "lang": "Brazilian Portuguese", "translated_lang": "Portugues do Brasil"}, {"abbr": "ps", "lang": "Pushto"}, {"abbr": "qu", "lang": "Quechua"}, {"abbr": "rm", "lang": "Romansh"}, {"abbr": "ro", "lang": "Romanian"}, {"abbr": "rn", "lang": "Rundi"}, - {"abbr": "ru", "lang": "Russian"}, + {"abbr": "ru", "lang": "Russian", "translated_lang": "Русский"}, {"abbr": "sg", "lang": "Sango"}, {"abbr": "sa", "lang": "Sanskrit"}, {"abbr": "si", "lang": "Sinhala"}, @@ -145,16 +146,16 @@ {"abbr": "sd", "lang": "Sindhi"}, {"abbr": "so", "lang": "Somali"}, {"abbr": "st", "lang": "Southern Sotho"}, - {"abbr": "es", "lang": "Spanish"}, + {"abbr": "es", "lang": "Spanish", "translated_lang": "Española"}, {"abbr": "sq", "lang": "Albanian"}, {"abbr": "sc", "lang": "Sardinian"}, {"abbr": "sr", "lang": "Serbian"}, {"abbr": "ss", "lang": "Swati"}, {"abbr": "su", "lang": "Sundanese"}, {"abbr": "sw", "lang": "Swahili (macrolanguage)"}, - {"abbr": "sv", "lang": "Swedish"}, + {"abbr": "sv", "lang": "Swedish", "translated_lang": "Svenska"}, {"abbr": "ty", "lang": "Tahitian"}, - {"abbr": "ta", "lang": "Tamil"}, + {"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்", "external_dep": true}, {"abbr": "tt", "lang": "Tatar"}, {"abbr": "te", "lang": "Telugu"}, {"abbr": "tg", "lang": "Tajik"}, @@ -165,11 +166,11 @@ {"abbr": "tn", "lang": "Tswana"}, {"abbr": "ts", "lang": "Tsonga"}, {"abbr": "tk", "lang": "Turkmen"}, - {"abbr": "tr", "lang": "Turkish"}, + {"abbr": "tr", "lang": "Turkish", "translated_lang" : "Türkçe"}, {"abbr": "tw", "lang": "Twi"}, {"abbr": "ug", "lang": "Uighur"}, {"abbr": "uk", "lang": "Ukrainian"}, - {"abbr": "ur", "lang": "Urdu"}, + {"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو", "external_dep": true}, {"abbr": "uz", "lang": "Uzbek"}, {"abbr": "ve", "lang": "Venda"}, {"abbr": "vi", "lang": "Vietnamese"}, @@ -180,5 +181,6 @@ {"abbr": "yi", "lang": "Yiddish"}, {"abbr": "yo", "lang": "Yoruba"}, {"abbr": "za", "lang": "Zhuang"}, - {"abbr": "zh", "lang": "Chinese"}, - {"abbr": "zu", "lang": "Zulu"}]
\ No newline at end of file + {"abbr": "zh-TW", "lang": "Traditional Chinese"}, + {"abbr": "zh-CN", "lang": "Simplified Chinese"}, + {"abbr": "zu", "lang": "Zulu"}] diff --git a/archinstall/locales/locales_generator.sh b/archinstall/locales/locales_generator.sh index 9432f83f..cdd5be31 100755 --- a/archinstall/locales/locales_generator.sh +++ b/archinstall/locales/locales_generator.sh @@ -7,6 +7,6 @@ find . -type f -iname "*.py" | xargs xgettext --join-existing --no-location --om for file in $(find locales/ -name "base.po"); do echo "Updating: $file" path=$(dirname $file) - msgmerge --quiet --no-location --width 512 --update $file locales/base.pot + msgmerge --quiet --no-location --width 512 --backup none --update $file locales/base.pot msgfmt -o $path/base.mo $file done diff --git a/archinstall/locales/nl/LC_MESSAGES/base.mo b/archinstall/locales/nl/LC_MESSAGES/base.mo Binary files differindex d7dcabc6..62b7af82 100644 --- a/archinstall/locales/nl/LC_MESSAGES/base.mo +++ b/archinstall/locales/nl/LC_MESSAGES/base.mo diff --git a/archinstall/locales/nl/LC_MESSAGES/base.po b/archinstall/locales/nl/LC_MESSAGES/base.po index b712d8ca..4eb93e22 100644 --- a/archinstall/locales/nl/LC_MESSAGES/base.po +++ b/archinstall/locales/nl/LC_MESSAGES/base.po @@ -256,10 +256,12 @@ msgstr "Taalvariant" msgid "Drive(s)" msgstr "Harde schijven" -msgid "Select disk layout" -msgstr "Kies een schijfindeling" +#, fuzzy +msgid "Disk layout" +msgstr "Schijfindeling vastleggen" -msgid "Set encryption password" +#, fuzzy +msgid "Encryption password" msgstr "Versleutelwachtwoord instellen" msgid "Swap" @@ -268,7 +270,8 @@ msgstr "Wisselgeheugen" msgid "Bootloader" msgstr "Opstartlader" -msgid "root password" +#, fuzzy +msgid "Root password" msgstr "Rootwachtwoord" msgid "Superuser account" @@ -426,8 +429,8 @@ msgstr "Bewerken" msgid "Delete" msgstr "Verwijderen" -msgid "Select an action for < {} >" -msgstr "Kies een actie voor < {} >" +msgid "Select an action for '{}'" +msgstr "Kies een actie voor '{}'" msgid "Copy to new key:" msgstr "Kopiëren naar nieuwe sleutel:" @@ -670,7 +673,7 @@ msgstr "" msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +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." @@ -757,6 +760,108 @@ msgstr "" "\n" "Kies welke partitie moet worden gemaskeerd alvorens te formatteren" +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Free space" +msgstr "" + +msgid "Bus-type" +msgstr "" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Stel een rootwachtwoord of minimaal één beheerder in" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Voer een gebruikersnaam in om een tweede account toe te voegen (laat leeg om over te slaan): " + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Subvolume :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Gebruiker verwijderen" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Druk op Esc om over te slaan\n" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + +#~ msgid "Select disk layout" +#~ msgstr "Kies een schijfindeling" + #~ msgid "Add :" #~ msgstr "Toevoegen:" diff --git a/archinstall/locales/pl/LC_MESSAGES/base.mo b/archinstall/locales/pl/LC_MESSAGES/base.mo Binary files differindex dc26f1d7..05fbedaf 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 d92637ad..9b12b024 100644 --- a/archinstall/locales/pl/LC_MESSAGES/base.po +++ b/archinstall/locales/pl/LC_MESSAGES/base.po @@ -1,21 +1,17 @@ msgid "" msgstr "" -"Project-Id-Version: \n" -"POT-Creation-Date: \n" -"PO-Revision-Date: \n" -"Last-Translator: Aleksandr Melman <Alexmelman88@gmail.com>\n" +"Last-Translator: MedzikUser <medzik@duck.com>\n" "Language-Team: \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.0.1\n" msgid "[!] A log file has been created here: {} {}" -msgstr "Plik dziennika został stworzony tutaj: {} {}" +msgstr "[!] Plik dziennika został stworzony tutaj: {} {}" msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" -msgstr " Proszę zgłosić ten błąd (i plik) pod adresem https://github.com/archlinux/archinstall/issues" +msgstr " Proszę zgłosić ten błąd (i dołączyć plik) pod adresem https://github.com/archlinux/archinstall/issues" msgid "Do you really want to abort?" msgstr "Czy napewno chcesz przerwać proces?" @@ -33,7 +29,7 @@ msgid "Username for required superuser with sudo privileges: " msgstr "Nazwa użytkownika dla wymaganego superużytkownika 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): " +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 superużytkownikiem (sudoer)?" @@ -42,7 +38,7 @@ msgid "Select a timezone" msgstr "Wybierz strefę czasową" msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" -msgstr "Czy chcesz użyć GRUB-a jako programu rozruchowego zamiast systemd-boot?" +msgstr "Czy chcesz użyć GRUB-a jako programu rozruchowego zamiast systemd-boot?" msgid "Choose a bootloader" msgstr "Wybierz program rozruchowy" @@ -217,10 +213,10 @@ msgid "Choose which kernels to use or leave blank for default \"{}\"" msgstr "Wybierz które jądra mają być używane, lub pozostaw puste dla ustawień domyślnych \"{}\"" msgid "Choose which locale language to use" -msgstr "Wybierz które locale języka mają zostać użyte" +msgstr "Wybierz które locale języka mają zostać użyte" msgid "Choose which locale encoding to use" -msgstr "Wybierz które locale kodowania mają zostać użyte" +msgstr "Wybierz które locale kodowania mają zostać użyte" msgid "Select one of the values shown below: " msgstr "Wybierz jedną z wartości przedstawionych poniżej: " @@ -428,8 +424,8 @@ msgstr "Edytuj" msgid "Delete" msgstr "Usuń" -msgid "Select an action for < {} >" -msgstr "Wybierz akcję dla < {} >" +msgid "Select an action for '{}'" +msgstr "Wybierz akcję dla '{}'" msgid "Copy to new key:" msgstr "Skopiuj do nowego klucza:" @@ -492,7 +488,7 @@ msgid "" "{}\n" "\n" "Select which partition to set subvolumes on" -msgstr "Wybierz partycję, na której mają być ustawione subwoluminów" +msgstr "Wybierz partycję, na której mają być ustawione subwoluminy" msgid "Manage btrfs subvolumes for current partition" msgstr "Zarządzaj subwoluminami btrfs dla bieżącej partycji" @@ -663,7 +659,8 @@ msgstr "Bardzo podstawowa instalacja pozwalająca ci dostosowanie Arch Linuxa do 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" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +#, 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" msgid "Installs a minimal system as well as xorg and graphics drivers." @@ -700,7 +697,7 @@ msgstr "" "zawiera partycje oczekujące w kolejce, to spowoduje ich usunięcie, czy jesteś pewien?" msgid "No audio server" -msgstr "" +msgstr "Brak serwera dźwięku" msgid "(default)" msgstr "(domyslne)" @@ -724,7 +721,7 @@ msgid "Edit: " msgstr "Edytuj: " msgid "Key: " -msgstr "" +msgstr "Klucz: " msgid "Edit {}: " msgstr "Edytuj {}: " @@ -737,14 +734,113 @@ msgid "Value: " msgstr "Wartość: " msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" -msgstr "" +msgstr "Możesz pominąć wybów 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 "" +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:" +msgid "Use HSM to unlock encrypted drive" +msgstr "Użyj HSM do odblokowania zaszyfrowanego dysku" + +msgid "Device" +msgstr "Urządzenie" + +msgid "Size" +msgstr "Rozmiar" + +msgid "Free space" +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" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Wprowadź nazwę użytkownika, aby utworzyć dodatkowego 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)?" + +#, fuzzy +msgid "Select which partitions to encrypt:" +msgstr "" +"{}\n" +"\n" +"Wybierz partycja która ma zostać zaszyfrowana" + +msgid "very weak" +msgstr "bardzo słabe" + +msgid "weak" +msgstr "słabe" + +msgid "moderate" +msgstr "umiarkowane" + +msgid "strong" +msgstr "mocne" + +#, fuzzy +msgid "Add subvolume" +msgstr "Subwolumin :{:16}" + +msgid "Edit subvolume" +msgstr "Edytuj wolumen" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Usuń użytkownika" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Kliknij ESC aby pominąć" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + #~ msgid "Select disk layout" #~ msgstr "Wybierz układ dysku" diff --git a/archinstall/locales/pt/LC_MESSAGES/base.mo b/archinstall/locales/pt/LC_MESSAGES/base.mo Binary files differindex 3b9f7c26..113b26a6 100644 --- a/archinstall/locales/pt/LC_MESSAGES/base.mo +++ b/archinstall/locales/pt/LC_MESSAGES/base.mo diff --git a/archinstall/locales/pt/LC_MESSAGES/base.po b/archinstall/locales/pt/LC_MESSAGES/base.po index 4352cf34..55569546 100644 --- a/archinstall/locales/pt/LC_MESSAGES/base.po +++ b/archinstall/locales/pt/LC_MESSAGES/base.po @@ -254,10 +254,12 @@ msgstr "Codificação de localização" msgid "Drive(s)" msgstr "Discos rígidos" -msgid "Select disk layout" -msgstr "Seleciona o esquema de disco" +#, fuzzy +msgid "Disk layout" +msgstr "Selecionar esquema de disco" -msgid "Set encryption password" +#, fuzzy +msgid "Encryption password" msgstr "Define a palavra-passe de encriptação" msgid "Swap" @@ -266,7 +268,8 @@ msgstr "Swap" msgid "Bootloader" msgstr "Carregador de arranque" -msgid "root password" +#, fuzzy +msgid "Root password" msgstr "Palavra-passe de root" msgid "Superuser account" @@ -429,8 +432,8 @@ msgid "Delete" msgstr "Eliminar" #, fuzzy -msgid "Select an action for < {} >" -msgstr "Selecione uma ação para < {} >" +msgid "Select an action for '{}'" +msgstr "Selecione uma ação para '{}'" msgid "Copy to new key:" msgstr "Copiar para nova chave:" @@ -688,7 +691,7 @@ msgstr "" msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +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." @@ -777,6 +780,110 @@ msgstr "" "\n" "Seleciona a partição a mascar para formatar" +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Free space" +msgstr "" + +msgid "Bus-type" +msgstr "" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "É necessário especificar uma senha de root ou pelo menos 1 super-utilizador" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Introduzir um nome de utilizador para criar um utilizador adicional (deixar em branco para saltar): " + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Subvolume :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Eliminar Utilizador" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "" +"Usa ESC para saltar\n" +"\n" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + +#~ msgid "Select disk layout" +#~ msgstr "Seleciona o esquema de disco" + #~ msgid "Add :" #~ msgstr "Adicionar :" diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.mo b/archinstall/locales/pt_BR/LC_MESSAGES/base.mo Binary files differindex 9c71d906..c66bae7f 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 35db5f95..73a25b19 100644 --- a/archinstall/locales/pt_BR/LC_MESSAGES/base.po +++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.po @@ -1,6 +1,9 @@ +# Translators: +# @Cain-dev (cain-dev.github.io) +# Rafael Fontenelle <rafaelff@gnome.org> msgid "" msgstr "" -"Last-Translator: @Cain-dev (cain-dev.github.io)\n" +"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -9,12 +12,8 @@ msgstr "" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Um arquivo de log foi criado aqui: {} {}" -msgid "" -" Please submit this issue (and file) to https://github.com/archlinux/" -"archinstall/issues" -msgstr "" -" Por favor, envie este problema (e o arquivo) para: " -"https://github.com/archlinux/archinstall/issues" +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " Por favor, envie este problema (e o arquivo) para: https://github.com/archlinux/archinstall/issues" msgid "Do you really want to abort?" msgstr "Deseja realmente abortar?" @@ -49,45 +48,29 @@ msgstr "Escolha um bootloader" msgid "Choose an audio server" msgstr "Escolha um servidor de áudio" -msgid "" -"Only packages such as base, base-devel, linux, linux-firmware, efibootmgr " -"and optional profile packages are installed." -msgstr "" -"Apenas pacotes como base, base-devel, linux, linux-firmware, efibootmgr " -"e pacotes opcionais de perfil são instalados." +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "Apenas pacotes como base, base-devel, linux, linux-firmware, efibootmgr e pacotes opcionais de perfil são instalados." -msgid "" -"If you desire a web browser, such as firefox or chromium, you may specify it " -"in the following prompt." -msgstr "" -"Se deseja um navegador web, como firefox ou chromium, pode especificá-lo " -"no próximo prompt." +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Se deseja um navegador web, como firefox ou chromium, pode especificá-lo no próximo prompt." -msgid "" -"Write additional packages to install (space separated, leave blank to skip): " -msgstr "" -"Digite pacotes adicionais para instalar (separados por espaço, deixe em branco para pular): " +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "Digite pacotes adicionais para instalar (separados por espaço, deixe em branco para pular): " msgid "Copy ISO network configuration to installation" msgstr "Copiar a configuração de rede da ISO para a instalação" -msgid "" -"Use NetworkManager (necessary to configure internet graphically in GNOME and " -"KDE)" -msgstr "" -"Usar NetworkManager (necessário para configurar internet graficamente no GNOME e " -"KDE)" +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Usar NetworkManager (necessário para configurar internet graficamente no GNOME e KDE)" msgid "Select one network interface to configure" msgstr "Selecione uma interface de rede para configurar" -msgid "" -"Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" -msgstr "" -"Selecione qual modo configurar para \"{}\" ou ignore para usar o modo padrão \"{}\"" +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "Selecione qual modo configurar para \"{}\" ou ignore para usar o modo padrão \"{}\"" msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " -msgstr "Digite o IP e a subrede para {} (exemplo: 192.168.0.5/24): " +msgstr "Digite o IP e a sub-rede para {} (exemplo: 192.168.0.5/24): " msgid "Enter your gateway (router) IP address or leave blank for none: " msgstr "Digite o seu IP de gateway (router) ou deixe em branco para nenhum: " @@ -105,7 +88,7 @@ msgid "" "Select what to do with\n" "{}" msgstr "" -"Selecione o que fazer com \n" +"Selecione o que fazer com\n" "{}" msgid "Enter a desired filesystem type for the partition" @@ -114,10 +97,8 @@ msgstr "Digite o tipo de sistema de arquivos desejado para a partição" msgid "Enter the start sector (percentage or block number, default: {}): " msgstr "Digite o setor de início (porcentagem ou número do bloco, padrão: {}): " -msgid "" -"Enter the end sector of the partition (percentage or block number, ex: {}): " -msgstr "" -"Digite o setor final da partição (porcentagem ou número de bloco, ex: {}): " +msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " +msgstr "Digite o setor final da partição (porcentagem ou número de bloco, ex.: {}): " msgid "{} contains queued partitions, this will remove those, are you sure?" msgstr "{} contém partições em fila, isto irá removê-las, tem certeza?" @@ -140,13 +121,8 @@ msgstr "" "\n" "Selecione por índice quais partições montar em" -msgid "" -" * Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -" * Os pontos de montagem das partições são relativos aos de dentro da instalação, boot " -"por exemplo seria /boot." - +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Os pontos de montagem das partições são relativos aos de dentro da instalação, boot por exemplo seria /boot." msgid "Select where to mount partition (leave blank to remove mountpoint): " msgstr "Selecione onde montar a partição (deixe em branco para remover o ponto de montagem): " @@ -176,7 +152,7 @@ msgid "" msgstr "" "{}\n" "\n" -"Selecione qual partição marcar como bootável" +"Selecione qual partição marcar como inicializável" msgid "" "{}\n" @@ -196,19 +172,14 @@ msgstr "Idioma do Archinstall" msgid "Wipe all selected drives and use a best-effort default partition layout" msgstr "Apagar todos os discos selecionados e usar um esquema de partições padrão de melhor desempenho" -msgid "" -"Select what to do with each individual drive (followed by partition usage)" -msgstr "" -"Selecione o que fazer com cada disco individual (seguido de uso da partição)" +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "Selecione o que fazer com cada disco individual (seguido de uso da partição)" msgid "Select what you wish to do with the selected block devices" msgstr "Selecione o que deseja fazer com os dispositivos de bloco selecionados" -msgid "" -"This is a list of pre-programmed profiles, they might make it easier to " -"install things like desktop environments" -msgstr "Esta é uma lista de perfis pré-programados, que podem por exemplo " -"facilitar a instalação de ambientes gráficos" +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "Esta é uma lista de perfis pré-programados, que podem por exemplo facilitar a instalação de ambientes gráficos" msgid "Select keyboard layout" msgstr "Selecione o layout de teclado" @@ -219,26 +190,14 @@ msgstr "Selecione uma das regiões de onde baixar os pacotes" msgid "Select one or more hard drives to use and configure" msgstr "Selecione um ou mais discos rígidos para usar e configurar" -msgid "" -"For the best compatibility with your AMD hardware, you may want to use " -"either the all open-source or AMD / ATI options." -msgstr "" -"Para melhor compatibilidade com o seu hardware AMD, talvez queira usar " -"a opção de drivers completamente open-source ou as opções da AMD / ATI." +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "Para melhor compatibilidade com o seu hardware AMD, talvez queira usar a opção de drivers completamente open-source ou as opções da 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 "" -"Para melhor compatibilidade com o seu hardware Intel, talvez queira usar " -"a opção de drivers completamente open-source ou as opções da Intel.\n" +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "Para melhor compatibilidade com o seu hardware Intel, talvez queira usar a opção de drivers completamente open-source ou as opções da Intel.\n" -msgid "" -"For the best compatibility with your Nvidia hardware, you may want to use " -"the Nvidia proprietary driver.\n" -msgstr "" -"Para melhor compatibilidade com o seu hardware Nvidia, talvez queira usar " -"o driver proprietário da Nvidia.\n" +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Para melhor compatibilidade com o seu hardware Nvidia, talvez queira usar o driver proprietário da Nvidia.\n" msgid "" "\n" @@ -270,13 +229,8 @@ msgstr "Selecione uma ou mais das opções abaixo: " msgid "Adding partition...." msgstr "Adicionando partição...." -msgid "" -"You need to enter a valid fs-type in order to continue. See `man parted` for " -"valid fs-type's." -msgstr "" -"Você precisa definir um tipo de sistema de arquivo válido. Consulte o `man parted` para " -"verificar os tipos de sistemas de arquivo válido." - +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Você precisa definir um tipo de sistema de arquivo válido. Consulte o `man parted` para verificar os tipos de sistemas de arquivo válido." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Erro: Listando os perfis em URL \"{}\" resulta em:" @@ -347,7 +301,7 @@ msgid "" "WARNING: Archinstall won't check the suitability of this setup\n" "Do you wish to continue?" msgstr "" -"Você decidiu ignorar a seleção de disco rídigo\n" +"Você decidiu ignorar a seleção de disco rígido\n" "e usar qualquer configuração de disco rígido montada em {} (experimental)\n" "ATENÇÃO: O Archinstall não verifica a viabilidade desta configuração\n" "Deseja continuar?" @@ -374,7 +328,7 @@ msgid "Mark/Unmark a partition as encrypted" msgstr "Marcar/Desmarcar uma partição como encriptada" msgid "Mark/Unmark a partition as bootable (automatic for /boot)" -msgstr "Marcar/Desmarcar uma partição como bootável (automática para /boot)" +msgstr "Marcar/Desmarcar uma partição como inicializável (automática para /boot)" msgid "Set desired filesystem for a partition" msgstr "Definir o sistema de arquivos desejado para uma partição" @@ -425,26 +379,18 @@ msgstr "Digite uma senha de root (deixe em branco para desativar root): " msgid "Password for user \"{}\": " msgstr "Senha para o usuário \"{}\": " -msgid "" -"Verifying that additional packages exist (this might take a few seconds)" -msgstr "" -"Verificando se existem pacotes adicionais (isto pode demorar alguns segundos)" +msgid "Verifying that additional packages exist (this might take a few seconds)" +msgstr "Verificando se existem pacotes adicionais (isto pode demorar alguns segundos)" -msgid "" -"Would you like to use automatic time synchronization (NTP) with the default " -"time servers?\n" -msgstr "" -"Deseja usar sincronização de tempo automática (NTP) " -"com os servidores de tempo padrão?\n" +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "Deseja usar sincronização de tempo automática (NTP) com os servidores de tempo padrão?\n" msgid "" -"Hardware time and other post-configuration steps might be required in order " -"for NTP to work.\n" +"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 "" -"A hora de hardware e outros passos de pós-configuração podem ser necessários " -"para que o NTP funcione.\n" -"Para mais informações, por favor visite a Arch wiki" +"A hora de hardware e outros passos de pós-configuração podem ser necessários para que o NTP funcione.\n" +"Para mais informações, por favor visite a wiki do Arch" msgid "Enter a username to create an additional user (leave blank to skip): " msgstr "Digite um nome de usuário para criar um usuário adicional (deixe em branco para pular): " @@ -454,12 +400,10 @@ msgstr "Use ESC para pular\n" msgid "" "\n" -" Choose an object from the list, and select one of the available actions for " -"it to execute" +" Choose an object from the list, and select one of the available actions for it to execute" msgstr "" "\n" -" Escolha um objeto da lista, e selecione uma das ações disponíveis " -"para executar" +" Escolha um objeto da lista, e selecione uma das ações disponíveis para executar" msgid "Cancel" msgstr "Cancelar" @@ -479,8 +423,8 @@ msgstr "Editar" msgid "Delete" msgstr "Deletar" -msgid "Select an action for < {} >" -msgstr "Selecione uma ação para < {} >" +msgid "Select an action for '{}'" +msgstr "Selecione uma ação para '{}'" msgid "Copy to new key:" msgstr "Copiar para nova chave:" @@ -495,17 +439,11 @@ msgstr "" "\n" "Esta é a configuração escolhida escolhida por você:" -msgid "" -"Pacman is already running, waiting maximum 10 minutes for it to terminate." -msgstr "" -"O Pacman já está a rodando, aguarde no máximo até 10 minutos para terminar." +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "O Pacman já está em execução, aguarde no máximo até 10 minutos para terminar." -msgid "" -"Pre-existing pacman lock never exited. Please clean up any existing pacman " -"sessions before using archinstall." -msgstr "" -"Pacman lock não terminou. Por favor, limpe as sessões " -"de pacman existentes antes de usar o archinstall." +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "A trava pré-existente do Pacman não terminou. Por favor, limpe as sessões de pacman existentes antes de usar o archinstall." msgid "Choose which optional additional repositories to enable" msgstr "Escolha quais repositórios adicionais opcionais ativar" @@ -517,7 +455,7 @@ msgid "Change password" msgstr "Mudar senha" msgid "Promote/Demote user" -msgstr "Promover/Demover usuário" +msgstr "Promover/Rebaixar usuário" msgid "Delete User" msgstr "Deletar usuário" @@ -530,7 +468,7 @@ msgstr "" "Definir um novo usuário\n" msgid "User Name : " -msgstr "Nome de Usuário : " +msgstr "Nome de usuário : " msgid "Should {} be a superuser (sudoer)?" msgstr "{} deve ser um superusuário (sudoer)?" @@ -578,7 +516,7 @@ msgid "Enter a directory for the configuration(s) to be saved: " msgstr "Digite um diretório para as configurações serem salvas: " msgid "Not a valid directory: {}" -msgstr "Não é um diretorio válido: {}" +msgstr "Não é um diretório válido: {}" msgid "The password you are using seems to be weak," msgstr "A senha que está usando parece ser fraca," @@ -656,12 +594,8 @@ msgstr "Deseja usar a compressão BTRFS?" msgid "Would you like to create a separate partition for /home?" msgstr "Deseja criar uma partição separada para /home?" -msgid "" -"The selected drives do not have the minimum capacity required for an " -"automatic suggestion\n" -msgstr "" -"As unidades selecionadas não tem a capacidade mínima para " -"sugestão automática\n" +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "As unidades selecionadas não tem a capacidade mínima para sugestão automática\n" msgid "Minimum capacity for /home partition: {}GB\n" msgstr "Capacidade mínima para partição /home : {}GB\n" @@ -685,7 +619,7 @@ msgid "Manual configuration setting must be a list" msgstr "O ajuste de configuração manual deve ser em lista" msgid "No iface specified for manual configuration" -msgstr "iface não especificado para configuração manual" +msgstr "iface não especificada para configuração manual" msgid "Manual nic configuration with no auto DHCP requires an IP address" msgstr "A configuração manual de NIC sem DHCP automático requer um endereço IP" @@ -708,41 +642,23 @@ msgstr "Configuração manual" msgid "Mark/Unmark a partition as compressed (btrfs only)" msgstr "Marcar/desmarcar a partição como comprimida (apenas btrfs)" -msgid "" -"The password you are using seems to be weak, are you sure you want to use it?" -msgstr "" -"A senha que você está usando parece ser fraca, tem certeza que deseja utilizá-la?" +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "A senha que você está usando parece ser fraca, tem certeza que deseja utilizá-la?" -msgid "" -"Provides a selection of desktop environments and tiling window managers, e." -"g. gnome, kde, sway" -msgstr "" -"Proporciona uma seleção de ambientes gráficos e gerenciadores de janela como por exemplo " -"gnome, kde, sway" +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "Proporciona uma seleção de ambientes gráficos e gerenciadores de janela como por exemplo gnome, kde, sway" msgid "Select your desired desktop environment" msgstr "Selecione o ambiente gráfico desejado" -msgid "" -"A very basic installation that allows you to customize Arch Linux as you see " -"fit." -msgstr "" -"Uma instalação bem básica que permite a você customizar o Arch Linux " -"como desejar." +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Uma instalação bem básica que permite a você customizar o Arch Linux como desejar." -msgid "" -"Provides a selection of various server packages to install and enable, e.g. " -"httpd, nginx, mariadb" -msgstr "" -"Proporciona uma seleção de diversos pacotes de servidor para instalar e habilitar " -"como por exemplo httpd, nginx, mariadb" +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "Proporciona uma seleção de diversos pacotes de servidor para instalar e habilitar como por exemplo httpd, nginx, mariadb" -msgid "" -"Choose which servers to install, if none then a minimal installation wil be " -"done" -msgstr "" -"Selecione quais servidores instalar, se há nenhum uma instalação mínima será " -"feita" +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Selecione quais servidores instalar, se há nenhum uma instalação mínima será feita" msgid "Installs a minimal system as well as xorg and graphics drivers." msgstr "Instala um sistema mínimo assim como xorg e drivers de vídeo." @@ -750,28 +666,20 @@ msgstr "Instala um sistema mínimo assim como xorg e drivers de vídeo." msgid "Press Enter to continue." msgstr "Tecle Enter para continuar." -msgid "" -"Would you like to chroot into the newly created installation and perform " -"post-installation configuration?" -msgstr "" -"Deseja fazer chroot para a nova instalação e realizar " -"configurações pós-instalação?" +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "Deseja fazer chroot para a nova instalação e realizar configurações pós-instalação?" msgid "Are you sure you want to reset this setting?" -msgstr "Tem certeza que desejar resetar essa configuração?" +msgstr "Tem certeza que desejar redefinir essa configuração?" msgid "Select one or more hard drives to use and configure\n" msgstr "Selecione uma ou mais unidades para usar e configurar\n" msgid "Any modifications to the existing setting will reset the disk layout!" -msgstr "Quaisquer modificações para configurações existentes vão resetar o layout de disco!" +msgstr "Quaisquer modificações para configurações existentes vão redefinir o layout de disco!" -msgid "" -"If you reset the harddrive selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Se você resetar a seleção de unidades isso também resetará o layout " -"da unidade atual. Tem certeza?" +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "Se você redefinir a seleção de unidades isso também redefinirá o layout da unidade atual. Tem certeza?" msgid "Save and exit" msgstr "Salvar e sair" @@ -781,7 +689,7 @@ msgid "" "contains queued partitions, this will remove those, are you sure?" msgstr "" "{}\n" -"contém partições enfileiradas partitions, isso irá removê-las, tem certeza?" +"contém partições enfileiradas, isso irá removê-las, tem certeza?" msgid "No audio server" msgstr "Sem servidor de áudio" @@ -796,7 +704,7 @@ msgid "" "Use CTRL+C to reset current selection\n" "\n" msgstr "" -"Use CTRL+C para resetar a seleção atual\n" +"Use CTRL+C para redefinir a seleção atual\n" "\n" msgid "Copy to: " @@ -817,15 +725,101 @@ msgstr "Adicionar: " msgid "Value: " msgstr "Valor: " -msgid "" -"You can skip selecting a drive and partitioning and use whatever drive-setup " -"is mounted at /mnt (experimental)" -msgstr "" -"Você pode ignorar a seleção de unidade e particionar seja lá o que estiver " -"montado em /mnt (experimental)" +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "Você pode ignorar a seleção de unidade e particionar seja lá o que estiver montado em /mnt (experimental)" msgid "Select one of the disks or skip and use /mnt as default" msgstr "Selecione um dos discos ou ignore e use /mnt como padrão" msgid "Select which partitions to mark for formatting:" msgstr "Selecione quais partições marcar para formatar:" + +msgid "Use HSM to unlock encrypted drive" +msgstr "Usar HSM para desbloquear unidade encriptada" + +msgid "Device" +msgstr "Dispositivo" + +msgid "Size" +msgstr "Tamanho" + +msgid "Free space" +msgstr "Espaço livre" + +msgid "Bus-type" +msgstr "Tipo de barramento" + +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Deve-se especificar uma senha de root ou pelo menos 1 usuário com privilégios de sudo" + +msgid "Enter username (leave blank to skip): " +msgstr "Digite um nome de usuário (deixe em branco para pular): " + +msgid "The username you entered is invalid. Try again" +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 "very weak" +msgstr "muito fraca" + +msgid "weak" +msgstr "fraca" + +msgid "moderate" +msgstr "moderada" + +msgid "strong" +msgstr "forte" + +msgid "Add subvolume" +msgstr "Adicionar subvolume" + +msgid "Edit subvolume" +msgstr "Editar subvolume" + +msgid "Delete subvolume" +msgstr "Deletar subvolume" + +msgid "Configured {} interfaces" +msgstr "{} interfaces configuradas" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Use ESC para pular" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/ru/LC_MESSAGES/base.mo b/archinstall/locales/ru/LC_MESSAGES/base.mo Binary files differindex be3405fe..8b3f0ae4 100644 --- a/archinstall/locales/ru/LC_MESSAGES/base.mo +++ b/archinstall/locales/ru/LC_MESSAGES/base.mo diff --git a/archinstall/locales/ru/LC_MESSAGES/base.po b/archinstall/locales/ru/LC_MESSAGES/base.po index 27f86e23..6d5799eb 100644 --- a/archinstall/locales/ru/LC_MESSAGES/base.po +++ b/archinstall/locales/ru/LC_MESSAGES/base.po @@ -9,19 +9,14 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" -"X-Generator: Poedit 3.0.1\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"X-Generator: Poedit 3.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 " 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 "Вы действительно хотите прекратить?" @@ -36,13 +31,10 @@ msgid "Desired hostname for the installation: " msgstr "Желаемое имя хоста для установки: " msgid "Username for required superuser with sudo privileges: " -msgstr "" -"Имя пользователя для требуемого суперпользователя с привилегиями sudo: " +msgstr "Имя пользователя для требуемого суперпользователя с привилегиями sudo: " msgid "Any additional users to install (leave blank for no users): " -msgstr "" -"Любые дополнительные пользователи для установки (оставьте пустым, если " -"пользователей нет): " +msgstr "Любые дополнительные пользователи для установки (оставьте пустым, если пользователей нет): " msgid "Should this user be a superuser (sudoer)?" msgstr "Должен ли этот пользователь быть суперпользователем (sudoer)?" @@ -59,59 +51,38 @@ 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 "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 "" -"Если вы хотите использовать веб-браузер, например, firefox или chromium, вы " -"можете указать его в следующем запросе." +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Если вы хотите использовать веб-браузер, например, firefox или chromium, вы можете указать его в следующем запросе." -msgid "" -"Write additional packages to install (space separated, leave blank to skip): " -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 "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 "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-адрес вашего шлюза (маршрутизатора) или оставьте пустым, если его " -"нет: " +msgstr "Введите IP-адрес вашего шлюза (маршрутизатора) или оставьте пустым, если его нет: " msgid "Enter your DNS servers (space separated, blank for none): " msgstr "Введите ваши DNS-серверы (через пробел, пустой - нет): " msgid "Select which filesystem your main partition should use" -msgstr "" -"Выберите, какую файловую систему должен использовать ваш основной раздел" +msgstr "Выберите, какую файловую систему должен использовать ваш основной раздел" msgid "Current partition layout" msgstr "Текущая разметка разделов" @@ -129,10 +100,8 @@ 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 "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 "{} содержит разделы в очереди, это удалит их, вы уверены?" @@ -155,17 +124,11 @@ msgstr "" "\n" "Выберите по индексу, какой раздел куда монтировать" -msgid "" -" * Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -" * Точки монтирования разделов являются относительными внутри установки, " -"например, загрузочный будет /boot." +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 "" -"Выберите куда монтировать раздел (оставьте пустым, чтобы удалить точку " -"монтирования): " +msgstr "Выберите куда монтировать раздел (оставьте пустым, чтобы удалить точку монтирования): " msgid "" "{}\n" @@ -210,25 +173,16 @@ msgid "Archinstall language" msgstr "Язык Archinstall" msgid "Wipe all selected drives and use a best-effort default partition layout" -msgstr "" -"Стереть все выбранные диски и использовать оптимальную схему разделов по " -"умолчанию" +msgstr "Стереть все выбранные диски и использовать оптимальную схему разделов по умолчанию" -msgid "" -"Select what to do with each individual drive (followed by partition usage)" -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 "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 "Выберите раскладку клавиатуры" @@ -237,29 +191,16 @@ msgid "Select one of the regions to download packages from" msgstr "Выберите один из регионов для загрузки пакетов" msgid "Select one or more hard drives to use and configure" -msgstr "" -"Выберите один или несколько жестких дисков для использования и настройте их" +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 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 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 "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Для наилучшей совместимости с оборудованием Nvidia вы можете использовать проприетарный драйвер Nvidia.\n" msgid "" "\n" @@ -268,15 +209,13 @@ msgid "" msgstr "" "\n" "\n" -"Выберите графический драйвер или оставьте пустым, чтобы установить все " -"драйверы с открытым исходным кодом" +"Выберите графический драйвер или оставьте пустым, чтобы установить все драйверы с открытым исходным кодом" msgid "All open-source (default)" msgstr "Все с открытым исходным кодом (по умолчанию)" msgid "Choose which kernels to use or leave blank for default \"{}\"" -msgstr "" -"Выберите, какие ядра использовать, или оставьте пустым по умолчанию \"{}\"." +msgstr "Выберите, какие ядра использовать, или оставьте пустым по умолчанию \"{}\"." msgid "Choose which locale language to use" msgstr "Выберите, какой язык локали использовать" @@ -293,12 +232,8 @@ 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-тип. Смотрите `man " -"parted` для правильных fs-типов." +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Чтобы продолжить, вам нужно ввести действительный fs-тип. Смотрите `man parted` для правильных fs-типов." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Ошибка: Перечисление профилей по URL \"{}\" привело к:" @@ -370,8 +305,7 @@ msgid "" "Do you wish to continue?" msgstr "" "Вы решили пропустить выбор жесткого диска\n" -"и будете использовать любой диск, смонтированный по адресу {} " -"(экспериментально)\n" +"и будете использовать любой диск, смонтированный по адресу {} (экспериментально)\n" "ПРЕДУПРЕЖДЕНИЕ: Archinstall не будет проверять пригодность этой установки.\n" "Вы хотите продолжить?" @@ -391,16 +325,13 @@ msgid "Assign mount-point for a partition" msgstr "Назначить точку монтирования для раздела" msgid "Mark/Unmark a partition to be formatted (wipes data)" -msgstr "" -"Пометить/снять отметку с раздела, который будет отформатирован (стирание " -"данных)" +msgstr "Пометить/снять отметку с раздела, который будет отформатирован (стирание данных)" msgid "Mark/Unmark a partition as encrypted" msgstr "Пометить/снять отметку с раздела как зашифрованный" msgid "Mark/Unmark a partition as bootable (automatic for /boot)" -msgstr "" -"Пометить/снять отметку с раздела как загрузочный (автоматически для /boot)" +msgstr "Пометить/снять отметку с раздела как загрузочный (автоматически для /boot)" msgid "Set desired filesystem for a partition" msgstr "Установите желаемую файловую систему для раздела" @@ -440,8 +371,7 @@ msgid "Enter a encryption password for {}" msgstr "Введите пароль шифрования для {}" msgid "Enter disk encryption password (leave blank for no encryption): " -msgstr "" -"Введите пароль шифрования диска (оставьте пустым для отсутствия шифрования): " +msgstr "Введите пароль шифрования диска (оставьте пустым для отсутствия шифрования): " msgid "Create a required super-user with sudo privileges: " msgstr "Создайте необходимого суперпользователя с привилегиями sudo: " @@ -452,43 +382,31 @@ msgstr "Введите пароль root (оставьте пустым, что msgid "Password for user \"{}\": " msgstr "Пароль для пользователя \"{}\": " -msgid "" -"Verifying that additional packages exist (this might take a few seconds)" -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 "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" +"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" +"Для работы NTP может потребоваться аппаратное время и другие шаги после конфигурации.\n" "Для получения дополнительной информации, пожалуйста, ознакомьтесь с ArchWiki" msgid "Enter a username to create an additional user (leave blank to skip): " -msgstr "" -"Введите имя пользователя для создания дополнительного пользователя (оставьте " -"пустым, чтобы пропустить): " +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" +" Choose an object from the list, and select one of the available actions for it to execute" msgstr "" "\n" -" Выберите объект из списка и выберите одно из доступных действий для его " -"выполнения" +" Выберите объект из списка и выберите одно из доступных действий для его выполнения" msgid "Cancel" msgstr "Отменить" @@ -508,8 +426,8 @@ msgstr "Редактировать" msgid "Delete" msgstr "Удалить" -msgid "Select an action for < {} >" -msgstr "Выберите действие для < {} >" +msgid "Select an action for '{}'" +msgstr "Выберите действие для '{}'" msgid "Copy to new key:" msgstr "Копировать в новый ключ:" @@ -524,17 +442,11 @@ msgstr "" "\n" "Это выбранная вами конфигурация:" -msgid "" -"Pacman is already running, waiting maximum 10 minutes for it to terminate." -msgstr "" -"Pacman уже запущен, ожидание его завершения составляет максимум 10 минут." +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 не завершилась. Пожалуйста, очистите " -"все существующие сессии pacman перед использованием archinstall." +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "Существовавшая ранее блокировка pacman не завершилась. Пожалуйста, очистите все существующие сессии pacman перед использованием archinstall." msgid "Choose which optional additional repositories to enable" msgstr "Выберите, какие дополнительные репозитории следует включить" @@ -625,8 +537,7 @@ msgid "Missing configurations:\n" msgstr "Отсутствующие конфигурации:\n" msgid "Either root-password or at least 1 superuser must be specified" -msgstr "" -"Должен быть указан либо пароль root, либо как минимум 1 суперпользователь" +msgstr "Должен быть указан либо пароль root, либо как минимум 1 суперпользователь" msgid "Manage superuser accounts: " msgstr "Управление учетными записями суперпользователей: " @@ -686,12 +597,8 @@ 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 "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" @@ -718,9 +625,7 @@ msgid "No iface specified for manual configuration" msgstr "Не указан iface для ручной настройки" msgid "Manual nic configuration with no auto DHCP requires an IP address" -msgstr "" -"Ручная конфигурация сетевого адаптера без автоматического DHCP требует IP-" -"адреса" +msgstr "Ручная конфигурация сетевого адаптера без автоматического DHCP требует IP-адреса" msgid "Add interface" msgstr "Добавить интерфейс" @@ -740,74 +645,44 @@ 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 "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 "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 "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 "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 wil be " -"done" -msgstr "" -"Выберите серверы для установки, если их нет, то будет выполнена минимальная " -"установка" +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 и графические драйверы." +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 "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" +msgstr "Выберите один или несколько жестких дисков для использования и настройки\n" msgid "Any modifications to the existing setting will reset the disk layout!" -msgstr "" -"Любые изменения существующей настройки приведут к сбросу разметки диска!" +msgstr "Любые изменения существующей настройки приведут к сбросу разметки диска!" -msgid "" -"If you reset the harddrive selection this will also reset the current disk " -"layout. Are you sure?" -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 "Сохранить и выйти" @@ -853,12 +728,8 @@ 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 "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 по умолчанию" @@ -881,12 +752,8 @@ 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 "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 "Введите имя пользователя (оставьте пустым, чтобы пропустить): " @@ -897,14 +764,80 @@ 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] > " + #, python-brace-format #~ msgid "Edit {origkey} :" #~ msgstr "Редактировать {origkey}:" #~ msgid "Archinstall requires root privileges to run. See --help for more." -#~ msgstr "" -#~ "Для запуска Archinstall требуются привилегии root. Для получения " -#~ "дополнительной информации смотрите --help." +#~ msgstr "Для запуска Archinstall требуются привилегии root. Для получения дополнительной информации смотрите --help." #~ msgid " ! Formatting {archinstall.arguments['harddrives']} in " #~ msgstr " ! Форматирование {archinstall.arguments['harddrives']} в " diff --git a/archinstall/locales/sv/LC_MESSAGES/base.mo b/archinstall/locales/sv/LC_MESSAGES/base.mo Binary files differindex b7999fbb..f2798bd4 100644 --- a/archinstall/locales/sv/LC_MESSAGES/base.mo +++ b/archinstall/locales/sv/LC_MESSAGES/base.mo diff --git a/archinstall/locales/sv/LC_MESSAGES/base.po b/archinstall/locales/sv/LC_MESSAGES/base.po index 2c587af5..9d7f7455 100644 --- a/archinstall/locales/sv/LC_MESSAGES/base.po +++ b/archinstall/locales/sv/LC_MESSAGES/base.po @@ -256,10 +256,12 @@ msgstr "Teckenuppsättning du vill använda" msgid "Drive(s)" msgstr "Hårddiskar" -msgid "Select disk layout" -msgstr "Välj hårddisk-layout" +#, fuzzy +msgid "Disk layout" +msgstr "Spara disk konfigurering" -msgid "Set encryption password" +#, fuzzy +msgid "Encryption password" msgstr "Välj ett krypterings-lösenord" msgid "Swap" @@ -268,7 +270,8 @@ msgstr "Swap" msgid "Bootloader" msgstr "Boot-loader" -msgid "root password" +#, fuzzy +msgid "Root password" msgstr "root-lösenord" msgid "Superuser account" @@ -426,8 +429,8 @@ msgstr "Editera" msgid "Delete" msgstr "Ta bort" -msgid "Select an action for < {} >" -msgstr "Välj vad du vill göra med < {} >" +msgid "Select an action for '{}'" +msgstr "Välj vad du vill göra med '{}'" msgid "Copy to new key:" msgstr "Kopiera till en ny nyckel:" @@ -660,7 +663,8 @@ msgstr "En väldigt minimal installation som möjliggör konfigurering av Arch L msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "Erbjuder ett urval av olika server-packeteringar, t.ex. httpd, nginx och mariadb" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +#, fuzzy +msgid "Choose which servers to install, if none then a minimal installation will be done" msgstr "Välj vilka servrar du vill installera, en minimal installation sker om du hoppar över detta" msgid "Installs a minimal system as well as xorg and graphics drivers." @@ -736,3 +740,105 @@ msgstr "Välj en disk eller hoppa över och använd /mnt/archinstall utan format msgid "Select which partitions to mark for formatting:" msgstr "Välj vilken partition som skall markeras för formatering:" + +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Free space" +msgstr "" + +msgid "Bus-type" +msgstr "" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Antingen måste ett root-lösenord sättas eller 1 superanvändarkonto skapas" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Mata in ett användarnamn för att skapa ytterligare användare (lämna tom för att hoppa över): " + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " Sub-volym :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Ta bort användare" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Använd ESC för att hoppa över" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + +#~ msgid "Select disk layout" +#~ msgstr "Välj hårddisk-layout" diff --git a/archinstall/locales/ta/LC_MESSAGES/base.mo b/archinstall/locales/ta/LC_MESSAGES/base.mo Binary files differnew file mode 100644 index 00000000..2129b1fb --- /dev/null +++ b/archinstall/locales/ta/LC_MESSAGES/base.mo diff --git a/archinstall/locales/ta/LC_MESSAGES/base.po b/archinstall/locales/ta/LC_MESSAGES/base.po new file mode 100644 index 00000000..fa32830b --- /dev/null +++ b/archinstall/locales/ta/LC_MESSAGES/base.po @@ -0,0 +1,830 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: ta\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 இல் swap ஐப் பயன்படுத்த விரும்புகிறீர்களா?" + +msgid "Desired hostname for the installation: " +msgstr "நிறுவலுக்கு விரும்பிய ஹோஸ்ட்பெயர்: " + +msgid "Username for required superuser with sudo privileges: " +msgstr "சூடோ சிறப்புரிமைகளுடன் தேவைப்படும் சூப்பர் யூசருக்கான பயனர் பெயர்: " + +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'sக்கு `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 "நிறுவு ({} config(கள்) இல்லை)" + +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 "சூடோ சலுகைகளுடன் தேவையான சூப்பர் பயனரை உருவாக்கவும்: " + +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" +"மேலும் தகவலுக்கு, ஆர்ச் விக்கியைப் பார்க்கவும்" + +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 "பேக்மேன் ஏற்கனவே இயங்கி வருகிறது, அது முடிவடைவதற்கு அதிகபட்சம் 10 நிமிடங்கள் காத்திருக்கிறது." + +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "முன்பே இருக்கும் பேக்மேன் பூட்டு ஒருபோதும் வெளியேறவில்லை. archinstall ஐப் பயன்படுத்துவதற்கு முன், ஏற்கனவே உள்ள பேக்மேன் அமர்வுகளை சுத்தம் செய்யவும்." + +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 "சூடோ சிறப்புரிமை கொண்ட பயனர்களை வரையறுக்கவும்: " + +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 "ரூட்-கடவுச்சொல் அல்லது குறைந்தபட்சம் 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 "சூடோ சிறப்புரிமை கொண்ட பயனர்களை, பயனர் பெயரால் வரையறுக்கவும்: " + +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 "ஆர்ச் லினக்ஸ் பகிர்வுக்கான குறைந்தபட்ச கொள்ளளவு: {}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 "ஆர்ச் லினக்ஸை நீங்கள் பொருத்தமாகத் தனிப்பயனாக்க அனுமதிக்கும் மிக அடிப்படையான நிறுவல்." + +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 "ரூட்-கடவுச்சொல் அல்லது குறைந்தபட்சம் 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 " - முடக்கு/இயல்புநிலை: 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 "இணையான பதிவிறக்கங்கள்" + +#, fuzzy +msgid "ESC to skip" +msgstr "தவிர்க்க ESC ஐப் பயன்படுத்தவும்" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/tr/LC_MESSAGES/base.mo b/archinstall/locales/tr/LC_MESSAGES/base.mo Binary files differindex 6eb05010..6a205da9 100644 --- a/archinstall/locales/tr/LC_MESSAGES/base.mo +++ b/archinstall/locales/tr/LC_MESSAGES/base.mo diff --git a/archinstall/locales/tr/LC_MESSAGES/base.po b/archinstall/locales/tr/LC_MESSAGES/base.po index 03125510..c38f467e 100644 --- a/archinstall/locales/tr/LC_MESSAGES/base.po +++ b/archinstall/locales/tr/LC_MESSAGES/base.po @@ -15,12 +15,8 @@ msgstr "" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Burada bir günlük (log) dosyası oluşturuldu: {} {}" -msgid "" -" Please submit this issue (and file) to https://github.com/archlinux/" -"archinstall/issues" -msgstr "" -" Lütfen bu sorunu (ve dosyayı) https://github.com/archlinux/archinstall/" -"issues 'a bildirin" +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " Lütfen bu sorunu (ve dosyayı) https://github.com/archlinux/archinstall/issues 'a bildirin" msgid "Do you really want to abort?" msgstr "Gerçekten iptal etmek istiyor musunuz?" @@ -35,12 +31,10 @@ msgid "Desired hostname for the installation: " msgstr "Kurulum için tercih edilen bilgisayar ismi: " msgid "Username for required superuser with sudo privileges: " -msgstr "" -"Sudo yetkilerine sahip, gerekli bir süper kullanıcı için kullanıcı adı: " +msgstr "Sudo yetkilerine sahip, gerekli bir süper kullanıcı için kullanıcı adı: " msgid "Any additional users to install (leave blank for no users): " -msgstr "" -"Kurulum için ek kullanıcılar (ek kullanıcı istemiyorsanız boş bırakın): " +msgstr "Kurulum için ek kullanıcılar (ek kullanıcı istemiyorsanız boş bırakın): " msgid "Should this user be a superuser (sudoer)?" msgstr "Bu kullanıcı bir süper kullanıcı (sudoer) olmalı mı?" @@ -57,55 +51,35 @@ msgstr "Bir önyükleyici seçin" msgid "Choose an audio server" msgstr "Bir ses sunucusu seçin" -msgid "" -"Only packages such as base, base-devel, linux, linux-firmware, efibootmgr " -"and optional profile packages are installed." -msgstr "" -"Sadece base, base-devel, linux, linux-firmware, efibootmgr ve tercihi profil " -"paketleri kuruldu." +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "Sadece base, base-devel, linux, linux-firmware, efibootmgr ve tercihi profil paketleri kuruldu." -msgid "" -"If you desire a web browser, such as firefox or chromium, you may specify it " -"in the following prompt." -msgstr "" -"Eğer bir internet tarayıcısı arzu ediyorsanız, Firefox ya da Chromium gibi, " -"sıra gelen ekranda belirtebilirsiniz." +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Eğer bir internet tarayıcısı arzu ediyorsanız, Firefox ya da Chromium gibi, sıra gelen ekranda belirtebilirsiniz." -msgid "" -"Write additional packages to install (space separated, leave blank to skip): " -msgstr "" -"Kurulacak ek paketleri yazınız (boşlukla ayrılmış, geçmek için boş bırakın): " +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "Kurulacak ek paketleri yazınız (boşlukla ayrılmış, geçmek için boş bırakın): " msgid "Copy ISO network configuration to installation" msgstr "Kuruluma ISO'dan ağ yapılandırmasını kopyala" -msgid "" -"Use NetworkManager (necessary to configure internet graphically in GNOME and " -"KDE)" -msgstr "" -"NetworkManager'ı kullan (GNOME ya da KDE'de interneti grafik olarak " -"yapılandırmak için gerekli)" +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "NetworkManager'ı kullan (GNOME ya da KDE'de interneti grafik olarak yapılandırmak için gerekli)" msgid "Select one network interface to configure" msgstr "Yapılandırmak için bir ağ arayüzü seçin" -msgid "" -"Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" -msgstr "" -"\"{}\"i yapılandırmak için bir yöntem seçin ya da varsayılan yöntemi \"{}\" " -"kullanmak için geçin" +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "\"{}\"i yapılandırmak için bir yöntem seçin ya da varsayılan yöntemi \"{}\" kullanmak için geçin" msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " msgstr "{} için IP ve altağ girin (örnek: 192.168.0.5/24): " msgid "Enter your gateway (router) IP address or leave blank for none: " -msgstr "" -"Ağ geçidi (yönlendirici) IP adresini girin ya da kullanılmaması için boş " -"bırakın: " +msgstr "Ağ geçidi (yönlendirici) IP adresini girin ya da kullanılmaması için boş bırakın: " msgid "Enter your DNS servers (space separated, blank for none): " -msgstr "" -"DNS sunucularını girin (boşlukla ayrılmış, kullanılmaması için boş bırakın): " +msgstr "DNS sunucularını girin (boşlukla ayrılmış, kullanılmaması için boş bırakın): " msgid "Select which filesystem your main partition should use" msgstr "Ana disk bölümünde kullanması gereken dosya sistemini seçin" @@ -126,15 +100,11 @@ msgstr "Disk bölümü için arzu edilen bir dosya systemi tipi girin" msgid "Enter the start sector (percentage or block number, default: {}): " msgstr "Başlangıç kesimini girin (yüzde ya da blok numarası, varsayılan: {}): " -msgid "" -"Enter the end sector of the partition (percentage or block number, ex: {}): " -msgstr "" -"Disk bölümünün bitiş kesimini girin (yüzde ya da blok numarası, ör: {}): " +msgid "Enter the end sector of the partition (percentage or block number, ex: {}): " +msgstr "Disk bölümünün bitiş kesimini girin (yüzde ya da blok numarası, ör: {}): " msgid "{} contains queued partitions, this will remove those, are you sure?" -msgstr "" -"{} işlem sırasında bekleyen disk bölümleri bulunduruyor, bu onları " -"kaldıracak, emin misiniz?" +msgstr "{} işlem sırasında bekleyen disk bölümleri bulunduruyor, bu onları kaldıracak, emin misiniz?" msgid "" "{}\n" @@ -154,17 +124,11 @@ msgstr "" "\n" "Dizinden hangi disk bölümünün nereye mount (monte) edileceğini seçin" -msgid "" -" * Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -" * Disk bölümü mount (monte) noktaları iç kurulumla ilişkilidir, örnek " -"olarak boot, /boot olacaktır." +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Disk bölümü mount (monte) noktaları iç kurulumla ilişkilidir, örnek olarak boot, /boot olacaktır." msgid "Select where to mount partition (leave blank to remove mountpoint): " -msgstr "" -"Disk bölümünün nereye mount (monte) edileceğini seçin (mount noktasını " -"kaldırmak için boş bırakın): " +msgstr "Disk bölümünün nereye mount (monte) edileceğini seçin (mount noktasını kaldırmak için boş bırakın): " msgid "" "{}\n" @@ -209,25 +173,16 @@ msgid "Archinstall language" msgstr "Archinstall dili" msgid "Wipe all selected drives and use a best-effort default partition layout" -msgstr "" -"Bütün seçilmiş diskleri temizle ve elden gelen en iyi varsayılan disk bölümü " -"düzenini kullan" +msgstr "Bütün seçilmiş diskleri temizle ve elden gelen en iyi varsayılan disk bölümü düzenini kullan" -msgid "" -"Select what to do with each individual drive (followed by partition usage)" -msgstr "" -"Her bir disk ile ne yapılacağını seçin (disk bölümü kullanımı ile takip " -"edilir)" +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "Her bir disk ile ne yapılacağını seçin (disk bölümü kullanımı ile takip edilir)" msgid "Select what you wish to do with the selected block devices" msgstr "Seçili blok cihazları ile ne yapmak istediğinizi seçin" -msgid "" -"This is a list of pre-programmed profiles, they might make it easier to " -"install things like desktop environments" -msgstr "" -"Bu ön-programlanmış profillerin bir listesidir, bunlar masaüstü ortamları " -"gibi şeyler kurmayı kolaylaştırabilir" +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "Bu ön-programlanmış profillerin bir listesidir, bunlar masaüstü ortamları gibi şeyler kurmayı kolaylaştırabilir" msgid "Select keyboard layout" msgstr "Klavye düzeni seçin" @@ -238,26 +193,14 @@ msgstr "Paketleri indirmek için bölgelerden birini seçin" msgid "Select one or more hard drives to use and configure" msgstr "Kullanmak ve yapılandırmak için bir veya daha fazla sabit disk seçin" -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 donanımınızla en iyi uyumluluk için, tam açık-kaynak ya da AMD / ATI " -"ayarlarından birini kullanmak isteyebilirsiniz." +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 donanımınızla en iyi uyumluluk için, tam açık-kaynak ya da AMD / ATI ayarlarından birini kullanmak isteyebilirsiniz." -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 donanımınızla en iyi uyumluluk için, tam açık-kaynak ya da Intel " -"ayarlarından birini kullanmak isteyebilirsiniz.\n" +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 donanımınızla en iyi uyumluluk için, tam açık-kaynak ya da Intel ayarlarından birini kullanmak isteyebilirsiniz.\n" -msgid "" -"For the best compatibility with your Nvidia hardware, you may want to use " -"the Nvidia proprietary driver.\n" -msgstr "" -"Nvidia donanımınızla en iyi uyumluluk için, Nvidia patentli sürücüyü " -"kullanmak isteyebilirsiniz.\n" +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Nvidia donanımınızla en iyi uyumluluk için, Nvidia patentli sürücüyü kullanmak isteyebilirsiniz.\n" msgid "" "\n" @@ -266,16 +209,13 @@ msgid "" msgstr "" "\n" "\n" -"Bir grafik sürücüsü seçin ya da bütün açık-kaynak sürücüleri kurmak için boş " -"bırakın" +"Bir grafik sürücüsü seçin ya da bütün açık-kaynak sürücüleri kurmak için boş bırakın" msgid "All open-source (default)" msgstr "Tam açık-kaynak (varsayılan)" msgid "Choose which kernels to use or leave blank for default \"{}\"" -msgstr "" -"Hangi çekirdekleri kullanmak istediğinizi seçin ya da varsayılan \"{}\" için " -"boş bırakın" +msgstr "Hangi çekirdekleri kullanmak istediğinizi seçin ya da varsayılan \"{}\" için boş bırakın" # Burada "locale" hesaba özgü yani profil içinde yerel anlamına geliyor olabilir. Kurulumda ilgili metin ile karşılaşmadığımdan karar veremiyorum. msgid "Choose which locale language to use" @@ -295,12 +235,8 @@ msgstr "Aşağıdaki seçeneklerden bir ya da daha fazlasını seçin: " msgid "Adding partition...." msgstr "Disk bölümü ekleniyor…." -msgid "" -"You need to enter a valid fs-type in order to continue. See `man parted` for " -"valid fs-type's." -msgstr "" -"Devam etmek için geçerli bir ds-tipi (fs-type) girmeniz gerekiyor. Geçerli " -"ds-tiplerini görmek için `man parted`a bakın." +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Devam etmek için geçerli bir ds-tipi (fs-type) girmeniz gerekiyor. Geçerli ds-tiplerini görmek için `man parted`a bakın." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Hata: Bağlantı \"{}\"daki profilleri listeleme şöyle sonuçlandı:" @@ -394,17 +330,13 @@ msgid "Assign mount-point for a partition" msgstr "Bir disk bölümü için mount (monte) noktası ata" msgid "Mark/Unmark a partition to be formatted (wipes data)" -msgstr "" -"Bir disk bölümünü biçimlendirilmek üzere işaretle/işareti kaldır (veriyi " -"temizler)" +msgstr "Bir disk bölümünü biçimlendirilmek üzere işaretle/işareti kaldır (veriyi temizler)" msgid "Mark/Unmark a partition as encrypted" msgstr "Bir disk bölümünü şifrelenmiş olarak işaretle/işareti kaldır" msgid "Mark/Unmark a partition as bootable (automatic for /boot)" -msgstr "" -"Bir disk bölümünü boot edilebilir olarak işaretle/işareti kaldır (/boot için " -"otomatik)" +msgstr "Bir disk bölümünü boot edilebilir olarak işaretle/işareti kaldır (/boot için otomatik)" msgid "Set desired filesystem for a partition" msgstr "Bir disk bölümü için arzu edilen dosya sistemini ayarla" @@ -448,48 +380,36 @@ msgid "Create a required super-user with sudo privileges: " msgstr "Gerekli bir sudo yetkilerine sahip süper-kullanıcı oluşturun: " msgid "Enter root password (leave blank to disable root): " -msgstr "" -"Root (kök) şifresi girin (root'u hizmet dışı bırakmak için boş bırakın): " +msgstr "Root (kök) şifresi girin (root'u hizmet dışı bırakmak için boş bırakın): " msgid "Password for user \"{}\": " msgstr "Kullanıcı \"{}\" için şifre: " -msgid "" -"Verifying that additional packages exist (this might take a few seconds)" +msgid "Verifying that additional packages exist (this might take a few seconds)" msgstr "Ek paketlerin varlığı doğrulanıyor (bu bir kaç saniye alabilir)" -msgid "" -"Would you like to use automatic time synchronization (NTP) with the default " -"time servers?\n" -msgstr "" -"Varsayılan zaman sunucularıyla otomatik zaman eşzamanlamasını (NTP) " -"kullanmak ister misiniz?\n" +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "Varsayılan zaman sunucularıyla otomatik zaman eşzamanlamasını (NTP) kullanmak ister misiniz?\n" msgid "" -"Hardware time and other post-configuration steps might be required in order " -"for NTP to work.\n" +"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'nin çalışması için donanım zamanı ve diğer yapılandırma sonrası adımlar " -"gerekebilir.\n" +"NTP'nin çalışması için donanım zamanı ve diğer yapılandırma sonrası adımlar gerekebilir.\n" "Daha fazla bilgi için, lütfen Arch wikiye göz atın" msgid "Enter a username to create an additional user (leave blank to skip): " -msgstr "" -"Ek kullanıcı oluşturmak için bir kullanıcı adı girin (geçmek için boş " -"bırakın): " +msgstr "Ek kullanıcı oluşturmak için bir kullanıcı adı girin (geçmek için boş bırakın): " msgid "Use ESC to skip\n" msgstr "Geçmek için ESC'yi kullanın\n" msgid "" "\n" -" Choose an object from the list, and select one of the available actions for " -"it to execute" +" Choose an object from the list, and select one of the available actions for it to execute" msgstr "" "\n" -"Listeden bir obje seçin ve çalıştırılmak üzere mevcut eylemlerden birini " -"seçin" +"Listeden bir obje seçin ve çalıştırılmak üzere mevcut eylemlerden birini seçin" msgid "Cancel" msgstr "İptal et" @@ -509,8 +429,8 @@ msgstr "Düzenle" msgid "Delete" msgstr "Sil" -msgid "Select an action for < {} >" -msgstr "< {} > için bir eylem seçin" +msgid "Select an action for '{}'" +msgstr "'{}' için bir eylem seçin" msgid "Copy to new key:" msgstr "Yeni anahtara kopyala:" @@ -525,22 +445,14 @@ msgstr "" "\n" "Bu sizin seçilmiş yapılandırmanız:" -msgid "" -"Pacman is already running, waiting maximum 10 minutes for it to terminate." -msgstr "" -"Pacman hâlihazırda çalışıyor, işlemin sonlandırılması için en fazla 10 " -"dakika beklenecek." +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman hâlihazırda çalışıyor, işlemin sonlandırılması için en fazla 10 dakika beklenecek." -msgid "" -"Pre-existing pacman lock never exited. Please clean up any existing pacman " -"sessions before using archinstall." -msgstr "" -"Önceden var olan pacman kilidi çıkış yapmadı. Lütfen archinstall'ı " -"kullanmadan once mevcut olan pacman oturumlarını temizleyin." +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "Önceden var olan pacman kilidi çıkış yapmadı. Lütfen archinstall'ı kullanmadan once mevcut olan pacman oturumlarını temizleyin." msgid "Choose which optional additional repositories to enable" -msgstr "" -"Hangi tercihi ek repositorylerin (depoların) aktifleştirileceğini seçin" +msgstr "Hangi tercihi ek repositorylerin (depoların) aktifleştirileceğini seçin" msgid "Add a user" msgstr "Kullanıcı ekle" @@ -628,9 +540,7 @@ msgid "Missing configurations:\n" msgstr "Eksik yapılandırmalar:\n" msgid "Either root-password or at least 1 superuser must be specified" -msgstr "" -"Root (kök) şifresi ya da en azından 1 adet süper-kullanıcı belirtilmek " -"zorunda" +msgstr "Root (kök) şifresi ya da en azından 1 adet süper-kullanıcı belirtilmek zorunda" msgid "Manage superuser accounts: " msgstr "Süper-kullanıcı hesaplarını yönet: " @@ -690,12 +600,8 @@ msgstr "BTRFS sıkıştırmasını kullanmak ister misiniz?" msgid "Would you like to create a separate partition for /home?" msgstr "/home dizini için ayrı bir disk bölümü oluşturmak ister misiniz?" -msgid "" -"The selected drives do not have the minimum capacity required for an " -"automatic suggestion\n" -msgstr "" -"Seçilmiş diskler otomatik öneriler için gerekli minimum kapasiteye sahip " -"değil\n" +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "Seçilmiş diskler otomatik öneriler için gerekli minimum kapasiteye sahip değil\n" msgid "Minimum capacity for /home partition: {}GB\n" msgstr "/home disk bölümü için minimum kapasite: {}GB\n" @@ -740,43 +646,26 @@ msgid "Manual configuration" msgstr "Manuel yapılandırma" msgid "Mark/Unmark a partition as compressed (btrfs only)" -msgstr "" -"Bir disk bölümünü sıkıştırılmış olarak işaretle/işareti kaldır (sadece btrfs)" +msgstr "Bir disk bölümünü sıkıştırılmış olarak işaretle/işareti kaldır (sadece btrfs)" -msgid "" -"The password you are using seems to be weak, are you sure you want to use it?" -msgstr "" -"Kullandığınız şifre zayıf gözüküyor, kullanmak istediğinize emin misiniz?" +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "Kullandığınız şifre zayıf gözüküyor, kullanmak istediğinize emin misiniz?" -msgid "" -"Provides a selection of desktop environments and tiling window managers, e." -"g. gnome, kde, sway" -msgstr "" -"Masaüstü ortamları ve otomatik hizalamalı pencere yöneticilerine bir seçenek " -"sunar, örnek olarak gnome, kde, sway" +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "Masaüstü ortamları ve otomatik hizalamalı pencere yöneticilerine bir seçenek sunar, örnek olarak gnome, kde, sway" msgid "Select your desired desktop environment" msgstr "Arzu ettiğiniz masaüstü ortamını seçin" -msgid "" -"A very basic installation that allows you to customize Arch Linux as you see " -"fit." -msgstr "" -"Arch Linux'u istediğin gibi kişiselleştirmeni sağlayan çok basit bir kurulum." +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Arch Linux'u istediğin gibi kişiselleştirmeni sağlayan çok basit bir kurulum." -msgid "" -"Provides a selection of various server packages to install and enable, e.g. " -"httpd, nginx, mariadb" -msgstr "" -"Kurmak ve aktif etmek için bazı seçilmiş çeşitli sunucu paketleri sunar, " -"örnek olarak httpd, nginx, mariadb" +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "Kurmak ve aktif etmek için bazı seçilmiş çeşitli sunucu paketleri sunar, örnek olarak httpd, nginx, mariadb" -msgid "" -"Choose which servers to install, if none then a minimal installation wil be " -"done" -msgstr "" -"Hangi sunucuların kurulacağını seçin, eğer hiçbiri seçilmezse minimal bir " -"kurulum gerçekleştirilecektir" +#, fuzzy +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Hangi sunucuların kurulacağını seçin, eğer hiçbiri seçilmezse minimal bir kurulum gerçekleştirilecektir" msgid "Installs a minimal system as well as xorg and graphics drivers." msgstr "Xorg ve grafik sürücüleri ile minimal bir sistem kurar." @@ -784,29 +673,20 @@ msgstr "Xorg ve grafik sürücüleri ile minimal bir sistem kurar." msgid "Press Enter to continue." msgstr "Devam etmek için Enter'a bas." -msgid "" -"Would you like to chroot into the newly created installation and perform " -"post-installation configuration?" -msgstr "" -"Yeni oluşturulmuş kuruluma chroot etmek ve kurulum sonrası konfigürasyon " -"gerçekleştirmek ister misiniz?" +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "Yeni oluşturulmuş kuruluma chroot etmek ve kurulum sonrası konfigürasyon gerçekleştirmek ister misiniz?" msgid "Are you sure you want to reset this setting?" msgstr "Bu ayarı sıfırlamak istediğinize emin misiniz?" msgid "Select one or more hard drives to use and configure\n" -msgstr "" -"Kullanmak ve yapılandırmak için bir ya da daha fazla sabit disk seçin\n" +msgstr "Kullanmak ve yapılandırmak için bir ya da daha fazla sabit disk seçin\n" msgid "Any modifications to the existing setting will reset the disk layout!" msgstr "Mevcut ayara herhangi bir modifikasyon disk şemasını sıfırlayacaktır!" -msgid "" -"If you reset the harddrive selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Eğer sabit disk seçimini sıfırlarsanız bu ayrıca mevcut disk şemasını da " -"sıfırlayacaktır. Emin misiniz?" +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "Eğer sabit disk seçimini sıfırlarsanız bu ayrıca mevcut disk şemasını da sıfırlayacaktır. Emin misiniz?" msgid "Save and exit" msgstr "Kaydet ve çık" @@ -816,8 +696,7 @@ msgid "" "contains queued partitions, this will remove those, are you sure?" msgstr "" "{}\n" -"işlem sırasında bekleyen disk bölümleri bulunduruyor, bu onları kaldıracak, " -"emin misiniz?" +"işlem sırasında bekleyen disk bölümleri bulunduruyor, bu onları kaldıracak, emin misiniz?" msgid "No audio server" msgstr "Ses sunucusu yok" @@ -853,17 +732,11 @@ msgstr "Ekle: " msgid "Value: " msgstr "Değer: " -msgid "" -"You can skip selecting a drive and partitioning and use whatever drive-setup " -"is mounted at /mnt (experimental)" -msgstr "" -"Disk seçmeyi ve disk bölümlendirmeyi geçebilir ve disk kurulumu /mnt " -"dizininde neye mount (monte) ediliyse onu kullanabilirsiniz (deneysel)" +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "Disk seçmeyi ve disk bölümlendirmeyi geçebilir ve disk kurulumu /mnt dizininde neye mount (monte) ediliyse onu kullanabilirsiniz (deneysel)" msgid "Select one of the disks or skip and use /mnt as default" -msgstr "" -"Disklerden birini seçin ya da geçin ve /mnt dizinini varsayılan olarak " -"kullanın" +msgstr "Disklerden birini seçin ya da geçin ve /mnt dizinini varsayılan olarak kullanın" msgid "Select which partitions to mark for formatting:" msgstr "Biçimlendirme için işaretlenecek disk bölümünü seçin:" @@ -882,3 +755,87 @@ msgstr "Boş alan" msgid "Bus-type" msgstr "Bus(veri yolu)-tipi" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Root (kök) şifresi ya da en azından 1 adet süper-kullanıcı belirtilmek zorunda" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "Ek kullanıcı oluşturmak için bir kullanıcı adı girin (geçmek için boş bırakın): " + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +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 "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +#, fuzzy +msgid "Add subvolume" +msgstr " alt disk bölümü :{:16}" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +msgid "Delete subvolume" +msgstr "Kullanıcı Sil" + +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "Geçmek için ESC'yi kullanın" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" diff --git a/archinstall/locales/ur/LC_MESSAGES/base.mo b/archinstall/locales/ur/LC_MESSAGES/base.mo Binary files differindex dad80f9d..44e38ad4 100644 --- a/archinstall/locales/ur/LC_MESSAGES/base.mo +++ b/archinstall/locales/ur/LC_MESSAGES/base.mo diff --git a/archinstall/locales/ur/LC_MESSAGES/base.po b/archinstall/locales/ur/LC_MESSAGES/base.po index 9baa850c..8ab6c4e2 100644 --- a/archinstall/locales/ur/LC_MESSAGES/base.po +++ b/archinstall/locales/ur/LC_MESSAGES/base.po @@ -256,10 +256,12 @@ msgstr "مقامی انکوڈنگ" msgid "Drive(s)" msgstr "ہارڈ ڈرائیوز" -msgid "Select disk layout" -msgstr "ڈسک لے آؤٹ کو منتخب کریں" +#, fuzzy +msgid "Disk layout" +msgstr "ڈسک لے آؤٹ کو محفوظ کریں" -msgid "Set encryption password" +#, fuzzy +msgid "Encryption password" msgstr "انکرپشن پاس ورڈ سیٹ کریں" msgid "Swap" @@ -268,7 +270,8 @@ msgstr "سواپ" msgid "Bootloader" msgstr "بوٹ لوڈر" -msgid "root password" +#, fuzzy +msgid "Root password" msgstr "روٹ پاس ورڈ" msgid "Superuser account" @@ -424,8 +427,9 @@ msgstr "ترمیم" msgid "Delete" msgstr "حذف" -msgid "Select an action for < {} >" -msgstr "< {} > کے لیے ایک عمل منتخب کریں" +#, fuzzy +msgid "Select an action for '{}'" +msgstr "'{}' کے لیے ایک عمل منتخب کریں" msgid "Copy to new key:" msgstr "نئی کلید میں کاپی کریں:" @@ -672,7 +676,7 @@ msgstr "" msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" msgstr "" -msgid "Choose which servers to install, if none then a minimal installation wil be done" +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." @@ -759,6 +763,107 @@ msgstr "" "\n" "فارمیٹنگ کے لیے کس پارٹیشن کو ماسک کرنا ہے" +msgid "Use HSM to unlock encrypted drive" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Free space" +msgstr "" + +msgid "Bus-type" +msgstr "" + +#, fuzzy +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "روٹ پاس ورڈ یا کم از کم ۱ سپر یوزر کی وضاحت ہونی چاہیے" + +#, fuzzy +msgid "Enter username (leave blank to skip): " +msgstr "ایک اضافی صارف بنانے کے لیے صارف نام درج کریں (چھوڑنے کے لیے خالی چھوڑیں):" + +msgid "The username you entered is invalid. Try again" +msgstr "" + +#, fuzzy +msgid "Should \"{}\" be a superuser (sudo)?" +msgstr "کیا {} کو سپر یوزر (sudoer) ہونا چاہیے؟" + +#, fuzzy +msgid "Select which partitions to encrypt:" +msgstr "" +"{}\n" +"\n" +"منتخب کریں کہ کس پارٹیشن کو انکرپٹڈ یا خفیہ رکھنا ہے" + +msgid "very weak" +msgstr "" + +msgid "weak" +msgstr "" + +msgid "moderate" +msgstr "" + +msgid "strong" +msgstr "" + +msgid "Add subvolume" +msgstr "" + +msgid "Edit subvolume" +msgstr "" + +#, fuzzy +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 "" + +msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr "" + +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr "" + +#, python-brace-format +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "" + +msgid "Parallel Downloads" +msgstr "" + +#, fuzzy +msgid "ESC to skip" +msgstr "چھوڑنے کے لیے ESC استعمال کریں\n" + +msgid "CTRL+C to reset" +msgstr "" + +msgid "TAB to select" +msgstr "" + +#~ msgid "Select disk layout" +#~ msgstr "ڈسک لے آؤٹ کو منتخب کریں" + #~ msgid "Add :" #~ msgstr "شامل:" diff --git a/docs/index.rst b/docs/index.rst index 3e4b5203..a76a58d6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,7 +12,7 @@ Some of the features of Archinstall are: * **Context friendly.** The library always executes calls in sequential order to ensure installation-steps don't overlap or execute in the wrong order. It also supports *(and uses)* context wrappers to ensure cleanup and final tasks such as ``mkinitcpio`` are called when needed. -* **Full transparancy** Logs and insights can be found at ``/var/log/archinstall`` both in the live ISO and the installed system. +* **Full transparency** Logs and insights can be found at ``/var/log/archinstall`` both in the live ISO and the installed system. * **Accessibility friendly** Archinstall works with ``espeakup`` and other accessibility tools thanks to the use of a TUI. diff --git a/docs/installing/guided.rst b/docs/installing/guided.rst index 569b2d05..b7d4db4f 100644 --- a/docs/installing/guided.rst +++ b/docs/installing/guided.rst @@ -115,7 +115,7 @@ Options for ``--config`` +----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+ | hostname | any | Hostname of machine after installation. Default will be ``archinstall`` | No | +----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+ -| kernels | [ "kernel1", "kernel2"] | List of kernels to install eg: linux, linux-lts, linux-zen etc | Atleast 1 | +| kernels | [ "kernel1", "kernel2"] | List of kernels to install eg: linux, linux-lts, linux-zen etc | At least 1 | +----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+ | keyboard-language | Any valid layout given by ``localectl list-keymaps`` | eg: ``us``, ``de`` or ``de-latin1`` etc. Defaults to ``us`` | No | +----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+ @@ -149,7 +149,7 @@ Options for ``--config`` +----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+ .. note:: - [1] If no entires are found in ``harddrives``, archinstall guided installation will use whatever is mounted currently under ``/mnt/archinstall``. + [1] If no entries are found in ``harddrives``, archinstall guided installation will use whatever is mounted currently under ``/mnt/archinstall``. Options for ``--creds`` ----------------------- diff --git a/docs/pull_request_template.md b/docs/pull_request_template.md index 5e6daf51..731bed8f 100644 --- a/docs/pull_request_template.md +++ b/docs/pull_request_template.md @@ -1,15 +1,12 @@ -🚨 PR Guidelines: +- This fix issue: <!-- #13, #15 and #16 for instance. Or ignore if you're adding new functionality --> -# New features *(v2.2.0)* +## PR Description: -All future work towards *`v2.2.0`* is done against `master` now.<br> -Any patch work to existing versions will have to create a new branch against the tagged versions. +<!-- Please describe what changes this PR introduces, a good example would be: https://github.com/archlinux/archinstall/pull/1377 --> -# Describe your PR - -If the changes has been discussed in an Issue, please tag it so that we can backtrace from the issue later on.<br> -If the PR is larger than ~20 lines, please describe it here unless described in an issue. - -# Testing - -Any new feature or stability improvement should be tested if possible. Please follow the test instructions at the bottom of the README or use the ISO built on each PR. +## Tests and Checks +- [ ] I have tested the code!<br> + <!-- + After submitting your PR, an ISO can be downloaded below the PR description. After testing it you can check the box + You can do manual tests too, like isolated function tests, just something! + --> diff --git a/examples/guided.py b/examples/guided.py index 19b0d638..6f289caa 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -85,6 +85,10 @@ def ask_user_questions(): global_menu.enable('packages') + if archinstall.arguments.get('advanced', False): + # Enable parallel downloads + global_menu.enable('parallel downloads') + # Ask or Call the helper function that asks the user to optionally configure a network. global_menu.enable('nic') @@ -181,17 +185,22 @@ def perform_installation(mountpoint): archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium # Retrieve list of additional repositories and set boolean values appropriately - enable_testing = 'testing' in archinstall.arguments.get('additional-repositories', None) - enable_multilib = 'multilib' in archinstall.arguments.get('additional-repositories', None) + if archinstall.arguments.get('additional-repositories', None) is not None: + enable_testing = 'testing' in archinstall.arguments.get('additional-repositories', None) + enable_multilib = 'multilib' in archinstall.arguments.get('additional-repositories', None) + else: + enable_testing = False + enable_multilib = False if installation.minimal_installation(testing=enable_testing, multilib=enable_multilib): installation.set_locale(archinstall.arguments['sys-language'], archinstall.arguments['sys-encoding'].upper()) installation.set_hostname(archinstall.arguments['hostname']) - if archinstall.arguments['mirror-region'].get("mirrors", None) is not None: - installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium - if archinstall.arguments['swap']: + if archinstall.arguments.get('mirror-region') is not None: + if archinstall.arguments.get("mirrors", None) is not None: + installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium + if archinstall.arguments.get('swap'): installation.setup_swap('zram') - if archinstall.arguments["bootloader"] == "grub-install" and archinstall.has_uefi(): + if archinstall.arguments.get("bootloader") == "grub-install" and archinstall.has_uefi(): installation.add_additional_packages("grub") installation.add_bootloader(archinstall.arguments["bootloader"]) @@ -253,11 +262,13 @@ def perform_installation(mountpoint): if archinstall.arguments.get('custom-commands', None): archinstall.run_custom_user_commands(archinstall.arguments['custom-commands'], installation) + installation.genfstab() + installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") if not archinstall.arguments.get('silent'): prompt = str(_('Would you like to chroot into the newly created installation and perform post-installation configuration?')) choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run() - if choice == Menu.yes(): + if choice.value == Menu.yes(): try: installation.drop_to_shell() except: @@ -272,7 +283,7 @@ if not (archinstall.check_mirror_reachable() or archinstall.arguments.get('skip- archinstall.log(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.", level=logging.INFO, fg="red") exit(1) -if not archinstall.arguments.get('offline', False): +if not archinstall.arguments.get('offline'): latest_version_archlinux_keyring = max([k.pkg_version for k in archinstall.find_package('archlinux-keyring')]) # If we want to check for keyring updates diff --git a/examples/swiss.py b/examples/swiss.py index d0f02dc1..da45cd18 100644 --- a/examples/swiss.py +++ b/examples/swiss.py @@ -1,14 +1,14 @@ """ Script swiss (army knife) -Designed to make different workflows for the installation process. Which is controled by the argument --mode +Designed to make different workflows for the installation process. Which is controlled by the argument --mode mode full guides the full process of installation mode only_hd only proceeds to the creation of the disk infraestructure (partition, mount points, encryption) mode only_os processes only the installation of Archlinux and software at --mountpoint (or /mnt/archinstall) mode minimal (still not implemented) mode lineal. Instead of a menu, shows a sequence of selection screens (eq. to the old mode for guided.py) -When using the argument --advanced. an aditional menu for several special parameters needed during installation appears +When using the argument --advanced. an additional menu for several special parameters needed during installation appears This script respects the --dry_run argument @@ -158,29 +158,41 @@ class SetupMenu(archinstall.GeneralMenu): super().__init__(data_store=storage_area) def _setup_selection_menu_options(self): - self.set_option('archinstall-language', + self.set_option( + 'archinstall-language', archinstall.Selector( _('Archinstall language'), lambda x: self._select_archinstall_language(x), - default='English', - enabled=True)) - self.set_option('ntp', - archinstall.Selector( - 'Activate NTP', - lambda x: select_activate_NTP(), - default='Y', - enabled=True)) - self.set_option('mode', + display_func=lambda x: x.display_name, + default=self.translation_handler.get_language_by_abbr('en'), + enabled=True + ) + ) + + self.set_option( + 'ntp', + archinstall.Selector( + 'Activate NTP', + lambda x: select_activate_NTP(), + default='Y', + enabled=True + ) + ) + + self.set_option( + 'mode', archinstall.Selector( 'Excution mode', lambda x : select_mode(), default='full', - enabled=True)) + enabled=True) + ) + for item in ['LC_ALL','LC_CTYPE','LC_NUMERIC','LC_TIME','LC_MESSAGES','LC_COLLATE']: self.set_option(item, archinstall.Selector( f'{get_locale_mode_text(item)} locale', - lambda x,item=item: select_installed_locale(item), # the parmeter is needed for the lambda in the loop + lambda x,item=item: select_installed_locale(item), # the parameter is needed for the lambda in the loop enabled=True, dependencies_not=['LC_ALL'] if item != 'LC_ALL' else [])) self.option('LC_ALL').set_enabled(True) @@ -255,7 +267,7 @@ class MyMenu(archinstall.GlobalMenu): self.option(entry).set_enabled(False) self._update_install_text() - def post_callback(self,option,value=None): + def post_callback(self,option=None,value=None): self._update_install_text(self._execution_mode) def _missing_configs(self,mode='full'): @@ -286,7 +298,7 @@ class MyMenu(archinstall.GlobalMenu): """ -Instalation general subroutines +Installation general subroutines """ def get_current_status(): diff --git a/profiles/gnome.py b/profiles/gnome.py index d647ddc8..5e3a8da6 100644 --- a/profiles/gnome.py +++ b/profiles/gnome.py @@ -8,8 +8,7 @@ is_top_level_profile = False __packages__ = [ "gnome", "gnome-tweaks", - "gdm", - "gnome-software-packagekit-plugin", + "gdm" ] diff --git a/profiles/kde.py b/profiles/kde.py index 9edbe325..d32bf31b 100644 --- a/profiles/kde.py +++ b/profiles/kde.py @@ -12,7 +12,7 @@ __packages__ = [ "ark", "sddm", "plasma-wayland-session", - "egl-wayland", + "egl-wayland" ] diff --git a/profiles/server.py b/profiles/server.py index 21681c2f..f3e32d26 100644 --- a/profiles/server.py +++ b/profiles/server.py @@ -33,7 +33,7 @@ def _prep_function(*args, **kwargs): before continuing any further. """ choice = Menu(str(_( - 'Choose which servers to install, if none then a minimal installation wil be done')), + 'Choose which servers to install, if none then a minimal installation will be done')), available_servers, preset_values=kwargs['servers'], multi=True diff --git a/profiles/xorg.py b/profiles/xorg.py index 2ce8dcc2..de45acd3 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -47,9 +47,9 @@ if __name__ == 'xorg': for kernel in archinstall.storage['installation_session'].kernels: archinstall.storage['installation_session'].add_additional_packages(f"{kernel}-headers") # Fixes https://github.com/archlinux/archinstall/issues/585 archinstall.storage['installation_session'].add_additional_packages("dkms") # I've had kernel regen fail if it wasn't installed before nvidia-dkms - archinstall.storage['installation_session'].add_additional_packages("xorg-server xorg-xinit nvidia-dkms") + archinstall.storage['installation_session'].add_additional_packages("xorg-server", "xorg-xinit", "nvidia-dkms") else: - archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit {' '.join(archinstall.storage.get('gfx_driver_packages', []))}") + archinstall.storage['installation_session'].add_additional_packages(f"xorg-server", "xorg-xinit", *archinstall.storage.get('gfx_driver_packages', [])) elif 'amdgpu' in archinstall.storage.get("gfx_driver_packages", []): # The order of these two are important if amdgpu is installed #808 if 'amdgpu' in archinstall.storage['installation_session'].MODULES: @@ -60,9 +60,9 @@ if __name__ == 'xorg': archinstall.storage['installation_session'].MODULES.remove('radeon') archinstall.storage['installation_session'].MODULES.append('radeon') - archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit {' '.join(archinstall.storage.get('gfx_driver_packages', []))}") + archinstall.storage['installation_session'].add_additional_packages(f"xorg-server", "xorg-xinit", *archinstall.storage.get('gfx_driver_packages', [])) else: - archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit {' '.join(archinstall.storage.get('gfx_driver_packages', []))}") + archinstall.storage['installation_session'].add_additional_packages(f"xorg-server", "xorg-xinit", *archinstall.storage.get('gfx_driver_packages', [])) except Exception as err: archinstall.log(f"Could not handle nvidia and linuz-zen specific situations during xorg installation: {err}", level=logging.WARNING, fg="yellow") - archinstall.storage['installation_session'].add_additional_packages("xorg-server xorg-xinit") # Prep didn't run, so there's no driver to install + archinstall.storage['installation_session'].add_additional_packages("xorg-server", "xorg-xinit") # Prep didn't run, so there's no driver to install |